Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: s137 am 03. November 2014, 20:07
-
´Hallo zusammen,
Ich habe ein Problem bezüglich Interrupts/Exceptions und bin leider trotz sorgfäliger Analyse noch nicht dahinter gekommen wo genau mein Fehler liegt.
Ich habe eine Datei "idt.c" (siehe Anhang) in der (vlt noch etwas unsauber) meine Funktionen zum Laden und zur Initialisierung der IDT und die Funktionen zum Interrupthandling liegen.
Außerdem habe ich eine Datei "isr.S" (ebenfalls im Anhang) in der in Assemblercode die ISR's liegen.
Mein Problem ist jetzt dass ich nachdem ich in der "init.c" die GDT und die IDT initialisiert, sowie den PIC konfiguriert habe versuche testweise mit asm volatile("int $0x01");
die Exception Nr. 1 herbeizuführen, jedoch wird meine isr zur behandlung dabei nicht aufgerufen, die Exception also nicht behandelt -> Triple Fault -> Neustart des Rechners..
Die einzige Exception die ich fehlerfrei herbeiführen kann ist Nr. 0, dabei wird dann mein Handler aufgerufen und die Exception bearbeitet.
Schon mal Vielen Dank im Vorraus
s137
P.S. Einen Fehler der GDT kann ich ausschließen, diese habe ich schon seperat getetet.
-
Hi und willkommen an Board!
#define IDT_ENTRIES 1
Das sollte wohl mindestens 49 sein.
-
ach mist.. ich wusste doch ich hab was übersehen... imme diese leichsinnsfehler^^ hatte anfangs eben nur einen eintrag...
Vielen Dank für die Hilfe :) Es funktioniert jetzt einwandfrei^^
s137
-
Eine Frage noch, wieso passiert nichts, wenn ich Hardwareinterrupts aktiviere und Tasten auf der Tastatur drücke, das müsste doch eigtl IRQ's auslösen, die wiederrum behandelt werden?
Kann das daran liegen dass ich noch keinen Keyboardtreiber habe? Aber dan müsste ich doch immerhin den IRQ 0 vom Timer bekommen oder?
-
Ja, wenn du IRQs am PIC und in der CPU (mit STI) aktiviert hast, solltest du zumindest Timer Interrupts bekommen. Für Keyboardinterrupts musst du eventuell den Puffer vorher leeren (http://www.lowlevel.eu/wiki/KBC#Initialisierung), und bei jedem Keyboard-Interrupt ebenfalls aus dem Puffer lesen.
-
Also ich habe die IRQs in meiner init.c folgendermaßen (siehe unten) am PIC initialisiert und demaskiert und außerdem auch die Hardwareinterrupts (sti) eingeschaltet. Aber ich bekomme trotz Handling in meinem common InterruptHandler mit:
if (cpu->intr <= 0x1f) {
// kprintf("Exception %d, Kernel angehalten!\n", cpu->intr);
kputs("Exception: n/a, Kernel angehalten!\n");
// Hier den CPU-Zustand ausgeben
while(1) {
// Prozessor anhalten
asm volatile("cli; hlt");
}
} else {
// Hier den Hardwareinterrupt behandeln
kputs("Hardwareinterrupt");
if (cpu->intr >= 0x20 && cpu->intr <= 0x2f) {
if (cpu->intr == 0x20) {
kputs("Timerinterrupt");
}
if (cpu->intr == 0x21) {
kputs("Tastaturinterrupt");
}
if (cpu->intr >= 0x28) {
outb(0xa0, 0x20); // End of Interrupt: Slave PIC
}
outb(0x20, 0x20); // End of Interrupt: Master PIC
}
}
irgendwie keine Ausgabe...
Hier mal meine init.c:
#include "console.h"
#include "gdt.h"
#include "idt.h"
#include "keyboard.h"
static inline void outb(unsigned short port, unsigned char data)
{
asm volatile ("outb %0, %1" : : "a" (data), "Nd" (port));
}
void init(void)
{
// Global Descriptor Table initialisieren
init_gdt();
// Master-PIC initialisieren ( nur 7 IRQs )
outb(0x20, 0x11); // Initialisierungsbefehl fuer den PIC | CmdPort: 0x20
outb(0x21, 0x20); // Interruptnummer fuer IRQ 0 | DataPort: 0x21
outb(0x21, 0x04); // An IRQ 4 haengt der Master ?!
outb(0x21, 0x01); // ICW 4
// Slave-PIC initialisieren ( restliche IRQs )
outb(0xa0, 0x11); // Initialisierungsbefehl fuer den PIC | CmdPort: 0xA0
outb(0xa1, 0x28); // Interruptnummer fuer IRQ 8 | DataPort: 0xA1
outb(0xa1, 0x02); // An IRQ 2 haengt der Slave
outb(0xa1, 0x01); // ICW 4
// Alle IRQs aktivieren (demaskieren)
outb(0x20, 0x0);
outb(0xa0, 0x0);
// Interrupt Descriptor Table initialisieren
init_idt();
init_keyboard();
// Test Things
clrscr();
kputc('A', 0x01, 0, 0);
kputs("Hello World");
kputc('B', 0x04, 4, 5);
kputs("Test\n");
kputs("New Line?");
int a = kprintf("test\n");
kputn(a, 10);
// Aktivieren von Hardware Interrupts
asm volatile("sti");
}
Vielen Dank schonmal im Vorraus
s137
-
An dem Code, den du gepostet hast, liegts vermutlich nicht direkt. Zumindest kann ich da nichts entdecken. Ich halte es für am wahrscheinlichsten, dass anderer Code dazwischen funkt und die Interrupts sabotiert.
Hast du zum Beispiel diese Zeilen in entry.S aus dem Tutorial (ich nehme mal an dem folgst du) beachtet?
// Falls wir jemals aus init zurueckkommen sollten, sperren wir die Interrupts und
// halten einfach den Prozessor an. (man braucht ihn ja nicht unnötig heißlaufen lassen.)
_stop:
cli
hlt
-
und schon hab ich meinen Fehler gefunden.. vielen Dank nochmals ^^ die 2 zeilen sperren mir natürlich dank "cli" meine interrupts und halten dann den Prozessor an.. daran hab ich irgendwie gar nicht mehr gedacht...
doch wenn ich diese 2 zeilen entferne läuft der kernel ja iwie nicht weiter... also zumindest bekomme ich immernoch keine IRQ's... was kann ich machen um den Kernel am laufen zu halten?
-
ok frage hat sich erledigt.. eine einfach endlosschleife:
_furhter:
jmp _further
reicht aus ^^
-
Hallo,
du kannst in deine Endlosschlaufe noch ein "hlt" einbauen, dann läuft die CPU nicht "heiss". Sie hält eigentlich dann dort an mit arbeiten und nach einem Interrupt geht es hintendran weiter => Sprung zurück auf hlt.
Das hört man übrigens auch am Lüfter, wenn man sein OS auf echter Hardware testet. Wenn das "hlt" nicht steht, dann dreht der Lüfter "durch" :lol:
-
Dazu braucht man keine echte Hardware. qemu nimmt sich in dem Fall auch 100% CPU.
-
oh ok danke, werds so machen.
-
Ich habe gerade nochmal ein Problem das TSS betreffend. Ich gehe ja nach dem Tutorial vor und habe gerade den Userspace für das Multitasking implementiert in Form eines TSS. Allerdingt startet sich der Rechner nach der Initialisierung der GDT jedesmal neu.
Definiert ist mein TSS so:
static unsigned long tss[32] = { 0, 0, 0x10 };
und hier (innerhalb der init_gdt Funktion) wird das TSS in die GDT eingetragen und das Taskregister neu geladen:
set_entry(5, (unsigned long) tss, sizeof(tss), GDT_FLAG_TSS | GDT_FLAG_PRESENT | GDT_FLAG_RING3);
// Taskregister neu laden
asm volatile("ltr %%ax" : : "a" (5 << 3));
Wieso lädt der Rechner die GDT nicht ordnungsgemäß? Habe ich hier irgendwo einen Syntaxfehler gemacht?
Viele Grüße
s137
-
Was heißt "nach der Initialisierung der GDT" genau? Also bei welcher Codezeile kriegst du den Triple Fault?
Wo steht dein lgdt? Also hast du die GDT vor dem ltr überhaupt schon geladen?
-
Hier in der init.c habe ich mal provisorisch nach der Initialisierung der GDT, des PIC und der IDT:
// Global Descriptor Table initialisieren
init_gdt();
// Master-PIC initialisieren ( nur 7 IRQs )
outb(0x20, 0x11); // Initialisierungsbefehl fuer den PIC | CmdPort: 0x20
outb(0x21, 0x20); // Interruptnummer fuer IRQ 0 | DataPort: 0x21
outb(0x21, 0x04); // An IRQ 4 haengt der Master ?!
outb(0x21, 0x01); // ICW 4
// Slave-PIC initialisieren ( restliche IRQs )
outb(0xa0, 0x11); // Initialisierungsbefehl fuer den PIC | CmdPort: 0xA0
outb(0xa1, 0x28); // Interruptnummer fuer IRQ 8 | DataPort: 0xA1
outb(0xa1, 0x02); // An IRQ 2 haengt der Slave
outb(0xa1, 0x01); // ICW 4
// Alle IRQs aktivieren (demaskieren)
outb(0x20, 0x0);
outb(0xa0, 0x0);
// Interrupt Descriptor Table initialisieren
init_idt();
noch eine Endlosschleife mit asm volatile("cli; hlt;");
eingebaut um den Kernel mal dort anzuhalten und zu schauen ob er überhaupt soweit kommt. Ich weißt dass es nicht am PIC oder de IDT liegt, weil die GDT das einzige ist was ich verändert habe.
meine GDT wird nach dem ltr geladen.. ist das ein problem sollte das neuladen des TR's erst nach dem Laden der GDT erfolgen?
Edit: habs getestet, auch wenn das neuladen des TR's erst nach dem Laden der GDT erfolgt gibts nen Triple Fault..
-
Wie viele Einträge hat deine GDT und hat sie wirklich so viele Einträge?
-
ach man... ich hab schon wieder vegessen die Konstante anzupassen.. ich schäme mich grad wirklich dass ich den selben Fehler 2x gemacht habe...
Nochmals vielen Dank für deine Hilfe..
-
Bist nicht der erste, dem das passiert. Das ist zwar im Artikel erwähnt, aber sowas überliest man ja schnell.
-
Jaah stimmt auch wieder^^
Ja beim 2.Mal lesen merkt mans dann^^
Muss ich wohl irgendwie überlesen haben. Also tdem danke nochmal^^