Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: s137 am 29. November 2014, 15:11
-
Hallo zusammen,
Ich habe mittlerweile ein externes Testprogramm als flache Binary geschrieben und auch entsprechend als Mutlibootmodul geladen. Nur sobald ich mit dem im Tutorial gegebenen Code den Task (also das Multiboot Modul, sprich das externe Tetsprogramm) initialisieren möchte und danach die Hardwareinterrupts aktiviere, bekomme ich sofort nach der Aktivierung, einen Tastaturinterrupt, bei dem ich im Interrupthandler bisher nur eine kleine Infoausgabe definiert habe. Ich habe noch keine Keyboardtreiber und habe auch die Tastatur noch in keinster Weise aktiviert. Wie kann ich dann einen Tastaturinterrupt bekommen?
Vielen Dank schonmal für eure Hilfe
s137
-
Hallo,
Tastaturinterrupts kannst du trotzdem bekommen. Da ist es egal, ob du einen Treiber hast oder nicht. Du kannst aber die Tastaturinterrupts ausschalten, indem du beim PIC das entsprechende Bit löscht.
Weil du einen Tastaturinterrupt bekommst, heisst das wahrscheinlich dass irgendwann mal eine Taste gedrückt wurde.
Ich hoffe ich konnte dir helfen.
-
Oh ok, das mit dem PIC werd ich mal ausprobieren, aber ich habe definitv keine Taste gedrückt... Wenn dann erst nach dem Tastaturinterrupt...
-
Also gut habe mal mit "outb(0x20, 0x02);" den Tastaturinterrupt maskiert, bekomme jedoch weiterhin einen Tastaturinterrupt, und sonst nichts anderes.
Hier mal mein Interrupthandler:
struct cpu_state* handle_interrupt(struct cpu_state* cpu)
{
struct cpu_state* new_cpu = cpu;
if (cpu->intr <= 0x1f) {
// kprintf("Exception %d, Kernel angehalten!\n", cpu->intr);
kputs("Exception: ");
kputn(cpu->intr, 10);
kputs("\n Fehlercode: ");
kputn(cpu->error, 16);
debug(cpu, 1, "EXCEPTION:");
kputs("\n Kernel angehalten! \n");
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) {
new_cpu = schedule(cpu);
set_tss_entry(1, (unsigned long) (new_cpu + 1));
}
if (cpu->intr == 0x21) {
debug(cpu, 1, "Tastaturinterrupt:");
}
if (cpu->intr >= 0x28) {
outb(0xa0, 0x20); // End of Interrupt: Slave PIC
}
outb(0x20, 0x20); // End of Interrupt: Master PIC
}
if (cpu->intr == 0x30) {
new_cpu = syscall(cpu);
}
}
return new_cpu;
}
Danke schonmal für den Tipp mit dem PIC^^
-
Edit: Ich hatte den Falschen Befehl für das maskieren benutzt, es muss natürlich "outb(0x21, 0x02)" heißen... Zwar bekomme ich dann keinen Tastaturinterrupt mehr.. Das eigentliche Problem löst das aber nicht.. Denn mein Task wird trotzdem nicht ausgeführt... Es passiert dann einfach nichts... Und irgendwo muss der Tastaturinterrupt ja auch hergekommen sein, oder?
-
Den Tastaturinterrupt bekommt man typischerweise, weil man im Bootmenü Enter gedrückt hat. Den Makecode verarbeitet zwar GRUB noch, aber den Breakcode kriegt unter Umständen dein OS.
Wie du festgestellt hast, hat das aber mit deinem Problem eher nichts zu tun.
-
Ah ok, danke, das macht sinn :DD
Ich debugge, das ganze später mal noch ein bisschen mehr um rauszufinden an was es liegt..
-
Also beim Debugging des Tastaturinterrupts nach dem nichts mehr passiert, ist mir der veränderte EFLAGS Wert aufgefallen, welcher nicht 0x202 war, sonder 0x213, es waren also das Carry Flag und das Nested Task Flag gesetzt. Ich wüsste allerdings nicht wo ich in meinem Code einen "Overflow bei vorzeichenloser Berechnung" haben sollte… und den Zweck des "Nested Task Flag" hab ich auch noch nicht ganz verstanden...
-
Die gesetzen Flags in 0x213 sind das Direction Flag (0x200), das Auxilary Carry Flag (0x10) und das Carry Flag (0x1). Das Nested Task Flag ist 0x4000 und hier nicht gesetzt. Dass da Flags von arithmetischen Operationen gesetzt sind, ist ganz normal, denn dein Compiler generiert Code, der mathematische und logische Operationen enthält.
-
oh ok, danke :DD
naja ich habs jetzt (durch veränderungen im Userprogramm das als Multiboot Modul geladen wird) geschafft dass sich das Modul initialisert und ausgeführt wird, alerdings tritt direkt nach der Ausführung ein GPF auf mit dem Fehlercode: 2000. Diesen Fehlercode kann ich irgendiwe nicht genau analysieren, da dort ja keins der unteren Bits gesetzt ist.
Kann mir da irgendjemand weiterhelfen?
-
Keine gesetzten unteren Bits heißt, dass es sich um einen Fehler mit Bezug auf die GDT handelt. Es wird also vermutlich versucht 0x400 in ein Segmentregister zu laden. (Meine vermutete Ursache ist wie immer ein beschädigter oder falscher Stack.)
-
darf ich fragen wie du von dem Fehlercode 0x2000 auf 0x400 kommst?
-
Hast Recht. Ist Selektor 0x2000. Hab da wohl durch 8 dividiert, weil ich an Indizies gedacht habe.
-
Ich glaube ich weiß jetzt, was das Problem war... Ich hatte keine Endlosschleife in meinem externen Programm und sobald das Programm endet gabs die Exception... mein Kernel kann quasi nicht aus einem Task zurück in meine init (die aufrufende Funktion) springen, und dort in die Endlosschleife gehen. Wie kann ich das beheben? Momentan habe ich halt nur Tasks die eine Endlosschleife haben, also halt nie enden.
-
Da musst du einen Exit-Syscall implementieren, den jedes Programm am Ende aufrufen muss.
-
ah ok, Danke :DD aber wie genau realisiere ich sowas? muss ich mir vorher die adresse irgendwie merken zu der ich zurückspringen will? oder geht das irgendwie einfacher?
-
Das ist eigentlich ein Syscall, der einfach diesen Prozess löscht. Dann machst du noch einen Taskswitch oder wartest auf den nächsten Taskswitch.
Was bringt es dir zurück in den Kernel zu wechseln? Er wird nur noch über Syscall und Interrupts ausgeführt. Deshalb brauchst du auch keine Rücksprungaddresse.
-
Naja dass macht Sinnn.. aber wie lösche ich den Task aus einer verketteten Liste.. Ich weiß ja da nicht an welcher Stelle der Liste mein Task ist... Und ich kann ja aus dee Liste nicht einfach nen Eintrag rausnehmen, oder?
-
Eine Liste musst du durchsuchen, um einen bestimmten Task zu finden. Wenn du ihn kennst - und bei einer einfach verketteten Liste musst du auch den Task davor kennen, bei einer doppelt verketteten Liste nicht - dann kannst du auch Einträge aus der Mitte entfernen.
-
Ok danke, das heißt ich sollte meien Tasks erstmal eine eindeutige ID zuweisen...
-
Du hast ja einen Pointer auf den aktuellen Task, oder nicht? Den könntest du auch für die Suche nehmen.
-
ja stimmt daran habe ich gar nicht gedacht... Danke :DD
-
Noch eine andere Frage, ich implementiere gerade Paging, und ein Teil davon ist es ja am Ende des Interrupthandlers falls sich der Status der CPU geändert hat das neue Pagedirectory des aktuellen Tasks zu laden. Jetzt habe ich eine Datei idt.c in der mein Interrupthandler sowie das ganze Interruptzeug liegt und eine Datei task.c in der das ganze Zeug zum Initialisieren von Tasks und die schedule Funktion liegen. Weil ich jetzt im Interrupthandler auf das Pagedirectory des aktuellen Tasks zugreifen will, hab ich mir eine Funktion "getCurrentTask()" gebastelt die mir einen Pointer auf den aktuellen Task zurückgibt, allerdings bekomme ich immer die Fehlermeldung " Fehler: Dereferenzierung eines Zeigers auf unvollständigen Typen" wenn ich auf den Pointer zugreifen will.
Hier mal mein Code im Interrupthandler:
static struct task* c_task = NULL; // Diese Zeile steht weiter oben im Code
// Code am Ende des Interrupthandlers:
if (cpu != new_cpu) {
c_task = getCurrentTask();
asm volatile("mov %0, %%cr3" : : "r" (c_task->context->pagedir));
}
Und hier noch die Funktion:
struct task* getCurrentTask(void) {
if (current_task != NULL) {
return current_task;
}
return first_task;
}
-
Du hast wahrscheinlich vergessen die Headerdatei einzubinden oder die Struktur ist nicht definiert.
-
Nein eben nicht... die Struktur ist in der Headerdatei die ich eingebunden habe ^^ Hätte ich vlt noch erwähnen sollen..
-
Edit: Oh nein doch nicht... ich dachte das nur... ich dachte ich hatte die Struktur in der Headerdatei definiert... habs jetzt so dass es funktioniert. Danke
-
Ok danke, das heißt ich sollte meien Tasks erstmal eine eindeutige ID zuweisen...
Nein, ich meinte damit eher, dass es verschiedene Datenstrukturen mit verschiedenen Vor- und Nachteilen gibt. ;-)
Mit dem Pointer alleine kommst du klar, wenn du eine doppelt verkettete Liste baust.
-
Zur Identifikation reicht ein Pointer auch bei einer einfach verketteten Liste. Der Unterschied ist nur, dass man die einfach verkettete Liste noch durchgehen muss, während man bei der doppelten direkt an alles rankommt, was man verändern will.
-
Ah ok, danke :DD Dann werd ich mir mal doppelte verkettete Listen anschauen.. ist vermutlich einfacher :DD