Lowlevel

Lowlevel => Lowlevel-Coding => Thema gestartet von: micha am 18. March 2012, 18:26

Titel: Tastaturtreiber
Beitrag von: micha am 18. March 2012, 18:26
Hi
Ich bin grad dabei mir ein Tastaturtreiber zu programmieren.
Da hab ich nur ein Problem:
Wenn ich ein Befehl an die Tastatur sende wird eine #General Protection ausgelöst.

Hier der Code
kbc.h:
/**
 *  kernel/driver/kbc/kbc.h
 *  portdefinitionen & send_kbc_command
 *
 *  (C) Copyright 2012 Michael Sippel
 */
#ifndef _KBC_H
#define _KBC_H

#include <stdint.h>
#include <portio.h>

#define KBC_PORT_KBDCOMMAND   0x60 /* Befehl an Tastatur                */
#define KBC_PORT_KBCDATA      0x60 /* Daten-Puffer auslesen & schreiben */
#define KBC_PORT_KBCCOMMAND   0x64 /* Befehl an KBC                     */
#define KBC_PORT_KBCREGISTER  0x64 /* Statusregiser auslesen            */

#define KBC_COMM_P1_PORT   0xC0
#define KBC_COMM_READ_OPP  0xD0
#define KBC_COMM_WRITE_OPP 0xD1
#define KBC_COMM_READ_CCB  0x20
#define KBC_COMM_WRITE_CCB 0x60

#define KBC_COMMAND_OK 0xFA
/* ---------- Befehl an KBC senden -------------------- */
static uint8_t send_kbc_command(uint8_t port,uint8_t command){
  static int fz = 3; /// @p fz Fehlerzähler
  uint8_t ret;/// @p ret Rückgabe vom KBC
 
  //Warten bis Eigabepuffer leer ist
  while( inb(KBC_PORT_KBCREGISTER) & 0x2 );
  //KBC-Befehl senden
  outb(port, command);
  //Warten bis Antwort im Ausgabepuffer liegt
  while( inb(KBC_PORT_KBCREGISTER) & 0x1 );
  //Antwort einlesen
  ret = inb(KBC_PORT_KBCDATA);
  //Erfolgreich?
  if(ret = KBC_COMMAND_OK || fz > 2){
    fz = 3;//Fehlerzähler rücksetzen
    return ret;//ENDE
  }else{
    --fz;//Fehlerzähler dekremantieren
    send_kbc_command(port, command);//Nochmal versuchen
  }
}
/* ---------- Befehl an Tastatur senden --------------- */
static uint8_t send_kbd_command(uint8_t command){
  return send_kbc_command(KBC_PORT_KBDCOMMAND,command);
}
/* -- ENDE --- kbc.h -- */
#endif

keyboard.c:
/**
 *  kernel/driver/kbc/keyboard/init.c
 *  init_keyboard, keyboard_irq_handler
 *
 *  (C) Copyright 2012 Michael Sippel
 */
#include <stdint.h>
#include <portio.h>
#include <stdbool.h>
#include <console.h>

#include "kbc.h"

#define KBD_COMM_LEDS 0xED /* LEDS ansteuern        */
#define KBD_COMM_ECHO 0xEE /* Echo                  */
#define KBD_COMM_WDHR 0xF3 /* Wiederholrate setzen  */
#define KBD_COMM_ACTV 0xF4 /* Tastatur aktivieren   */
#define KBD_COMM_DAKV 0xF5 /* Tastatur deaktivieren */
#define KBD_COMM_STDW 0xF6 /* Standarderte setzen   */
#define KBD_COMM_KRST 0xFF /* Tastatur-Reset        */

#define KBD 0
/* ---------- Tastatur initalisieren ------------------ */
void init_keyboard(void){
  color = 0x0F;debug(KBD,"       \n");
  //Warten bis Tastatur nicht mehr im Resetmodus ist
  while(! inb(KBC_PORT_KBCREGISTER) & 0x4 );
 
  //Ausgabepuffer leeren
  while (inb(KBC_PORT_KBCREGISTER) & 0x1){
    //Solange Ausgabepuffer voll ist Datenregister lesen
    inb(KBC_PORT_KBCDATA);
  }
 
  //LEDs ausschalten
  send_kbd_command(KBD_COMM_LEDS);
  outb(KBC_PORT_KBCDATA, 0);

  //Schnellste Wiederholrate einstellen
  send_kbd_command(KBD_COMM_WDHR);
  outb(KBC_PORT_KBCDATA, 0);

  //Tastatur aktivieren
  send_kbd_command(KBD_COMM_ACTV);
}
/* ---------- IRQ handler für Tastatur ---------------- */
void keyboard_irq_handler(void){
  printf("Taste gedrückt!\n\n");
}
/* ------- ENDE -- keyboard.c --- */

Grüße
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 18. March 2012, 19:12
Zwei Fehler sind mir beim Überfliegen des Codes aufgefallen:

if(ret = KBC_COMMAND_OK || fz > 2){Du weist hier ret den Wert zu anstatt ihn zu vergleichen. Vergleiche gehen mit ==. Außerdem solltest du nochmal überlegen, was du dir mit der fz-Variable gedacht hast. Im jetzigen Zustand ist fz > 2 immer wahr, weil du fz mit 3 initialisierst.

while(! inb(KBC_PORT_KBCREGISTER) & 0x4 );Hier fehlen Klammern um inb(KBC_PORT_KBCREGISTER) & 0x4. Beide Sachen hätte dir der GCC auch gesagt, wenn du ihm -Wall als Parameter übergeben hättest.

Diese beiden Dinge verursachen für sich genommen allerdings noch keinen GPF. Du solltest mal versuchen die genaue Stelle des Absturzes (=Speicheradresse des Befehls) zu lokalisieren. Wenn du deinen Kernel mittels objdump mit den Parametern -dS disassemblierst, kannst du möglicherweise sogar die entsprechende Codezeile feststellen. Dazu musst du den Kernel mit dem Parameter -g kompilieren.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 21. March 2012, 15:03
Hallo!!
Hab' jetzt mein kernel mit -g kompiliert und dann folgendes gemacht:
ld -dS kernel -o kernel.txtDiese Datei kann ich mir mit oketa ansehen. Aber da steht nur Assemblierter Code drin.
War das gemeint?
Wenn ja, finde ich mich da nicht rein.

Gruß
Titel: Re: Tastaturtreiber
Beitrag von: kevin am 21. March 2012, 16:26
ld != objdump
Titel: Re: Tastaturtreiber
Beitrag von: micha am 21. March 2012, 19:43
das lässt sich jetzt dissasemblieren. Doch das passt nichgt alles in mein Terminal rein(der Anfang wird wieder gelöscht). Also kann ich nicht alles sehen. Den Parameter -o kennt objdump nicht.
gibt es da irgendwelche anderen?
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 21. March 2012, 19:51
Wenn du > kernel.txt an den Aufruf anhängst, wird die Ausgabe umgeleitet. Also sowas wie z.B. objdump -dS kernel.bin > kernel.txt

Das muss übrigens zwingend am Ende des Aufrufs stehen und funktioniert mit allen Programmen, die etwas ausgeben.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 21. March 2012, 19:57
So ich hab jetzt alles zusammen (C/asm)
... maximale zeichen erreicht ... im Anhang ist das zu groß .. und wie jetzt?
Titel: Re: Tastaturtreiber
Beitrag von: Svenska am 21. March 2012, 21:36
Pastebin
Titel: Re: Tastaturtreiber
Beitrag von: micha am 22. March 2012, 13:36
Hier liegts: http://pastebin.com/dgs0FNXK (http://pastebin.com/dgs0FNXK)
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 22. March 2012, 23:55
Damit kann ich erstmal nichts anfangen. Ich wollte, dass du rausfindest, an welcher Stelle der GPF auftritt, um damit den Fehler weiter einzugrenzen. Genauer gesagt, ist der Wert von EIP interessant. Den musst du dann in dem disassemblieren Code suchen. Du kannst den Wert von EIP von deinem eigenen Interrupthandler ausgeben lassen, oder (was zuverlässiger ist) das Log von qemu benutzen. Wenn du qemu mit den Parametern -d int aufrufst, erstellt es eine Datei namens qemu.log im aktuellen Verzeichnis oder in /tmp. Da musst du jetzt von oben angefangen den GPF suchen. Den GPF erkennst du vermutlich daran, dass die Zeile mit "0: v=0d ..." anfängt. In der selben Zeile sollte der Wert für EIP stehen.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 23. March 2012, 14:43
Eine Zeile, die mit
Zitat
"0: v=0d ..."
anfängt, gibt es zwar in meinem Logfile nicht, aber so eine ähnliche:      0: v=21 e=0000 i=0 cpl=0 IP=0008:001014fd pc=001014fd SP=0010:00106590 EAX=000000edund der Wert von EIP steht in dieser zeile nicht.
EIP steht viermal im logfile (mit verschiedenen werten)
Titel: Re: Tastaturtreiber
Beitrag von: micha am 23. March 2012, 15:43
Wenn das:
Zitat
001014fd
EIP sein soll, dann steht da ein nop.
Es steht nach call outb
Titel: Re: Tastaturtreiber
Beitrag von: kevin am 23. March 2012, 16:51
Ja, das ist eip (und das 0008 davor ist cs). v=21 heißt aber, dass es kein GPF ist, sondern Interrupt 0x21, also wahrscheinlich IRQ 1, der Tastaturinterrupt.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 23. March 2012, 16:56
Dann vertehe ich nicht, warum dann ein GPF ausgelöst wird und nicht mein irq handler.
?????
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 23. March 2012, 17:08
Folgt auf den Tastaturinterrupt eventuell noch ein weiterer Interrupt?
Titel: Re: Tastaturtreiber
Beitrag von: micha am 24. March 2012, 11:08
Ich hab da eine Vermutung.
Der Tastatur interrupt wird ausgelöst, aber es besitzt niemand die Privilegien, dies zu tun.
Das hab ich festgestellt, weil ich den interrupt auch nicht mit asm("int $0x21"); aufrufen kann. Statt dem IRQ kommt immer ein GPF.
Ich hab schon meine GDT verkleinert, dass ich nur noch ring 0 hab, aber das passiert trozdem.

Außerdem verstehe ich nicht, warum beim initalisieren der Tastatur der IRQ ausgelöst wird.

Gruß
Titel: Re: Tastaturtreiber
Beitrag von: micha am 28. March 2012, 16:40
Aha!
Ich kann nur die intr. bis 0x1f aufrufen (alle Exeptions) bei alen Anderen interrupts kommt ein GPF.
Ist möglicherweise der PIC falsch programmiert?

pic.c
/**
 *  kernel/interrupt/pic.c
 *  init_pic
 *
 *  (C) Copyright 2012 Michael Sippel
 */
#include <portio.h>
#include "interrupt.h"

#define PIC_MASTER_COMM    0x20
#define PIC_MASTER_DATA    (PIC_MASTER_COMM) + 1
#define PIC_SLAVE_COMM     0xa0
#define PIC_SLAVE_DATA     (PIC_SLAVE_COMM) + 1

#define PIC_INIT        0x11
#define PIC_ICW4        0x01
#define PIC_EOI         0x20

/* ---------- Initalisierung des PIC ------------------ */
void init_pic(void){
  // PICs initalisieren
  outb(PIC_MASTER_COMM,PIC_INIT);
  outb(PIC_SLAVE_COMM,PIC_INIT);
 
  //Erstes IRQ
  outb(PIC_MASTER_DATA, FIRST_IRQ);    // Master
  outb(PIC_SLAVE_DATA,  FIRST_IRQ + 8);// Slave
 
  //Slave auf IRQ 2 setzen
  outb(PIC_MASTER_DATA, 0x04);
  outb(PIC_SLAVE_DATA,  0x02);
 
  //ICW 4
  outb(PIC_MASTER_DATA, PIC_ICW4);// Master
  outb(PIC_SLAVE_DATA,  PIC_ICW4);// Slave
 
  // All IRQs aktivieren / demaskieren
  outb(PIC_MASTER_DATA, 0x0);
  outb(PIC_SLAVE_DATA,  0x0);
}

Eigentlich dürfte da nix falsch sein.

Was gibt es noch für mögliche fehler?
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 28. March 2012, 16:50
Ich denke, dass die Einträge in der IDT nicht korrekt sind.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 28. March 2012, 17:17
Denk ich nicht.
Die Testhandler (Hello-World-handler) fubktionieren, ABER nur auf den interrupts bis 0x1f

idt.c
/**
 *  kernel/interrupt/idt.h
 *  set_interrupt, init_idt, load_idt
 *
 *  (C) Copyright 2012 Michael Sippel
 */
#include <stdint.h>
#include <stdbool.h>

#include "handlerextern.h"
#include "interrupt.h"
/* ---------- Globale Variablen ----------------------- */
static uint64_t idt[IDT_ENTRIES]; //Interupt Deskriptor Table
/* ---------- Eintrag in die IDT setzen --------------- */
static void set_interrupt(int i, uint32_t offset, uint16_t selector, int type, bool present, int dpl){
  idt[i] = 0;
  //untere 32-Bit
  idt[i] = (offset & 0x0000ffff) | (selector << 16);
  //obere 32-Bit
  idt[i] |=(
    ( type << 8 ) |
    ( (dpl&3) << 13 ) |
    ( (present&1) << 15)|
    ( offset & 0xffff0000 )
   ) * 0x100000000;
}
/* ---------- IDT laden ------------------------------- */
void load_idt(void){
  struct {
    uint16_t size;
    uint64_t pointer;
  } __attribute__((packed)) idtp = {
    .size = IDT_ENTRIES - 1,
    .pointer = &idt,
  };
  asm("lidt %0" : : "m" (idtp));
}
/* ---------- IDT initalisieren ----------------------- */
void init_idt(void){
  ///           index, offset,                  selector,  type,  present, dpl
  set_interrupt(0x00, (uint32_t)&int_handler0x00,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x01, (uint32_t)&int_handler0x01,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x02, (uint32_t)&int_handler0x02,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x03, (uint32_t)&int_handler0x03,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x04, (uint32_t)&int_handler0x04,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x05, (uint32_t)&int_handler0x05,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x06, (uint32_t)&int_handler0x06,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x07, (uint32_t)&int_handler0x07,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x08, (uint32_t)&int_handler0x08,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x09, (uint32_t)&int_handler0x09,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0A, (uint32_t)&int_handler0x0A,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0B, (uint32_t)&int_handler0x0B,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0C, (uint32_t)&int_handler0x0C,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0D, (uint32_t)&int_handler0x0D,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0E, (uint32_t)&int_handler0x0E,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x0F, (uint32_t)&int_handler0x0F,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x10, (uint32_t)&int_handler0x10,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x11, (uint32_t)&int_handler0x11,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x12, (uint32_t)&int_handler0x12,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x13, (uint32_t)&int_handler0x13,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x14, (uint32_t)&int_handler0x14,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x15, (uint32_t)&int_handler0x15,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x16, (uint32_t)&int_handler0x16,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x17, (uint32_t)&int_handler0x17,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x18, (uint32_t)&int_handler0x18,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x19, (uint32_t)&int_handler0x19,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1A, (uint32_t)&int_handler0x1A,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1B, (uint32_t)&int_handler0x1B,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1C, (uint32_t)&int_handler0x1C,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1D, (uint32_t)&int_handler0x1D,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1E, (uint32_t)&int_handler0x1E,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
  set_interrupt(0x1F, (uint32_t)&int_handler0x1F,0x08,INTERRUPT_GATE,TRUE, 0  );//Exeption
     
  set_interrupt(0x20, (uint32_t)&int_handler0x20,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x21, (uint32_t)&int_handler0x21,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x22, (uint32_t)&int_handler0x22,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x23, (uint32_t)&int_handler0x23,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x24, (uint32_t)&int_handler0x24,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x25, (uint32_t)&int_handler0x25,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x26, (uint32_t)&int_handler0x26,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x27, (uint32_t)&int_handler0x27,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x28, (uint32_t)&int_handler0x28,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x29, (uint32_t)&int_handler0x29,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2A, (uint32_t)&int_handler0x2A,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2B, (uint32_t)&int_handler0x2B,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2C, (uint32_t)&int_handler0x2C,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2D, (uint32_t)&int_handler0x2D,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2E, (uint32_t)&int_handler0x2E,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ
  set_interrupt(0x2F, (uint32_t)&int_handler0x2F,0x08,INTERRUPT_GATE,TRUE, 0  );//IRQ

  set_interrupt(0x30, (uint32_t)&int_handler0x30,0x08,INTERRUPT_GATE,TRUE, 0  );//Software
  set_interrupt(0x31, (uint32_t)&test_int_handler00,0x08,INTERRUPT_GATE,TRUE,0);//Software
  set_interrupt(0x32, (uint32_t)&test_int_handler01,0x08,INTERRUPT_GATE,TRUE,0);//Software
}

/*----- ENDE idt.c ---- */
Titel: Re: Tastaturtreiber
Beitrag von: kevin am 28. March 2012, 17:35
Entschuldige die vielleicht blöde Frage, aber wie ist IDT_ENTRIES definiert?
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 28. March 2012, 18:02
.size = IDT_ENTRIES - 1,Hier gehört die Größe in Bytes (minus 1) hin, nicht die Anzahl der Einträge.

@taljeth:
scheinbar ist IDT_ENTRIES = 256
Titel: Re: Tastaturtreiber
Beitrag von: micha am 28. March 2012, 19:23
Richtig!
IDT_ENTRIES ist 256.
Wenn ich bei size IDT_ENTRIES * 8 nehme starte qemu bei jedem int. neu
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 28. March 2012, 21:13
du hast nicht mit IDT_ENTRIES * 8 - 1 probiert, oder? Die minus 1 war schon richtig.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 29. March 2012, 12:40
du hast nicht mit IDT_ENTRIES * 8 - 1 probiert, oder? Die minus 1 war schon richtig.
Na klar hab ich das!!!
Titel: Re: Tastaturtreiber
Beitrag von: micha am 29. March 2012, 16:46
Jetzt nochmal damit das klar ist:
 1. Ich nehme .size = IDT_ENTRIES -1
   - wenn IDT_ENTRIES = 256 ist funktioniert es
   - wenn IDT_ENTRIES = irgendwas anderes ist, startet qemu neu
 
 2. Ich nehme .size = IDT_ENTRIES * 8 -1
   - Es funktioniert immer, wenn IDT_ENTRIES größer als die wirkliche Anzahl der interrupts ist
      sonst bleibt qemu schwarz

Trotz dem bleibt ein Interrupt der >= 0x20 ist nicht ohne GPF
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 30. March 2012, 13:35
Steht vielleicht was interessantes im qemu.log?
Titel: Re: Tastaturtreiber
Beitrag von: micha am 30. March 2012, 14:02
wenn ich IDT_ENTRIES auf 256 gestetzt hab und *8 nehme wird der int erst ohne GPF audgelöst, springt in den handler und dann kommt der GPF.

im qemu.log steht eimal:
     0: v=21 e=0000 i=0 cpl=0 IP=0008:00101835 pc=00101835 SP=0010:00105f70 EAX=000000edund dann:
check_exception old: 0xffffffff new 0xd
     1: v=0d e=0204 i=0 cpl=0 IP=0008:00100d66 pc=00100d66 SP=0010:00105f6a EAX=00000000
Titel: Re: Tastaturtreiber
Beitrag von: kevin am 30. March 2012, 14:34
Der nächste Schritt ist dann zu schauen, welcher Code an 0x100d66 steht, der löst den GPF aus. Relativ wahrscheinlich ist, dass es der Rücksprung vom Interrupthandler ist, der schiefgeht.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 30. March 2012, 15:35
genau der ist es! :-)
und was ist daran jetzt falsch, das ein GPF ausgelöst wird :?
Titel: Re: Tastaturtreiber
Beitrag von: kevin am 30. March 2012, 15:42
Schau dir die Werte auf dem Stack an. In der Regel hast du dort zu viel liegen, weil du vergessen hast, was abzuräumen. Es kann auch mal passieren, dass zu wenig drauf liegt, wenn du mit dem Stackpointer irgendwo durcheinandergekommen bist. Oder selten, der Stackpointer ist richtig und nur der Inhalt stimmt nicht mehr.
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 30. March 2012, 16:01
Der Stackpointer sieht verdächtig aus. Er sollte eigentlich ein Vielfaches von 4 sein. Vielleicht hast du irgendwo ein word gepusht oder gepoppt.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 30. March 2012, 17:22
Ja, ESP ist nicht durch 4 teilbar. Ich hab nachgeschaut, ich hab immer versucht das `rechnen' mit dem Stackpointer zu vermeiden und bevor die komplette cpu gepopt wird nicht add $4, %esp sondern pop %eax verwendet. (%esp wegnehmen)
Beim wegnehmen der interruptnummer und dem Errorcode geht es ja nicht anders, da ist aber auch nichts (add $8, %esp).
Also ich hab' nicht mit irgendwelchen zahlen, die nicht durch 4 teibar sind, den Stackpointer verändert.
Wie könnten andere solche fehler entstehen?
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 30. March 2012, 17:29
Das kann zum Beispiel passieren, wenn push oder pop mit 16-bit Operanden verwendest. Also pushw/popw oder explizit ein 16-bit Register als Parameter übergeben. Allerdings ist das seltsam, dass der Stack trotzdem nicht ausgeglichen ist, außer du pusht etwas und nimmst es dann mit add/mov (oder anders) vom Stack, oder legst etwas mit sub/mov auf den Stack und poppst es.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 30. March 2012, 17:37
Eigentlich habe ich kein pushw/popw verwendet...
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 30. March 2012, 19:09
Ich denke dann bleibt dir nichts anderes übrig, als mit dem Debugger da ranzugehen. Du könntest zum Beispiel einen Breakpoint an den Anfang des Interrupthandlers setzen und ab da schrittweise durchgehen.

Dazu musst du GDB und den QEMU Monitor nehmen. Single-Stepping in Assembler kannst du in GDB mit stepi machen. Die Register kannst du dir im QEMU-Monitor mit info registers anzeigen lassen.

Ein paar Links:
http://www.lowlevel.eu/wiki/Debugging#bochs_.2F_QEMU
http://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#Continuing-and-Stepping
http://qemu-buch.de/de/index.php/QEMU-KVM-Buch/_Anhang/_QEMU-Monitor

Alternative wäre den kompletten Code irgendwo hochzuladen. Dann kann ich mir (oder wer anders) sich das mal angucken, und ich muss nicht mehr rumraten.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 31. March 2012, 15:26
Nun mit dem Debugger komme ich noch nicht wirklich zurecht.
Also ich mache bisjetzt folgendes:
gdb [dann kommt hier das file]
Bla.. BLa ...Bla
(gdb) target remote :1234

Zitat
[dann kommt hier das file]
soll ich da mein iso-image angeben?


und gleichzeitig:
qemu -S -cdrom image.iso
Und wie komme ich zu dem Qemu-Monitor?

Kann mir jemand den Debugger erklären? :?
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 31. March 2012, 16:05
Das Wichtige steht alles im Wiki-Artikel. GDB kriegt die Kernel-Binary als Parameter, und qemu musst du mit -s -S aufrufen. Du musst in gdb einen Breakpoint auf das Label mit dem Interrupthandler setzen mittels break intr_common_handler oder wie auch immer du das genannt hast. Dann startest du die Ausführung mit cont (oder c). Beim Interrupthandler angekommen, nutzt du stepi (oder si) um Schrittweise weiter zu gehen (oder du setzt halt mehr Breakpoints). Wenn du vorher einmal display/i $pc eingibst, zeigt dir GDB sogar immer den nächsten Assemblerbefehl an. In die Qemu-Konsole kommst du wenn du in Qemu Strg-Alt-2 drückst. Die Dokumentationen dazu hab ich ja bereits verlinkt.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 01. April 2012, 11:12
Ich kann jetzt mit dem Debugger arbeiten, ich komme auch an den Qemu-Monitor, doch dann ist meine Emulation verschwunden und die Register und der ganze andere kram passt auch nicht auf das kleine 80x25 "kästchen".
Also hab ich breakpoints (ohne Debugger) mit asm("int $3"); gesetzt und mir im qemu-log die Register angesehen:
Vor dem interruptaufruf war ESP ok. Nachher irgendwie falsch (kein vielfaches von vier). Aber mein Handler sieht nur so aus:
.extern keyboard_irq_handler

...

.global int_handler0x21
int_handler0x21:
    call keyboard_irq_handler
    iret

...
...

und wers wissen will..
void keyboard_irq_handler(void){
    printf("Taste gedrueckt!\n");
}

Ich mach nichts mit dem Stack.
könnte möglicherweise der Timerinterrupt dazwischen funken und der Stack verrutscht?
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 01. April 2012, 11:42
Das dir eine C-Funktion ESP verschiebt ist eher unwahrscheinlich. Ich weiß nicht genau wo bei dir vorher und nachher ist. Also direkt nach dem int_handler0x21 label und direkt vor dem iret müssen ESP, (und alle anderen Register auch) gleich sein. Es sieht so aus also würde es hier nicht an esp liegen (darum kümmert sich gcc) sondern an den anderen Registern die in keyboard_irq_handler verändert werden.

Edit: Eigentlich sollten die Fehler wegen falschen Register-Werten erst später auftreten und nicht schon beim iret. Wenn dein printf groben Unfug baut wäre es auch denkbar des es die Rücksprungadresse für den iret manipuliert. (mit var_args hättest du da zumindest die entsprechenden Pointer zu in der Hand)
Titel: Re: Tastaturtreiber
Beitrag von: micha am 01. April 2012, 14:02
Mein Printf (sprintf) habe ich ja selber implementiert, aber komplett in C. und ich glabe nicht, dass da was schief läuft. die cpu wird doch in einer C-Funktion gesichert.
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 01. April 2012, 14:13
Mein Printf (sprintf) habe ich ja selber implementiert, aber komplett in C. und ich glabe nicht, dass da was schief läuft.
ich habe auch nicht erwartet das du da Assmebler benutzt hast ^^
Zitat
die cpu wird doch in einer C-Funktion gesichert.
Nein! Nicht alle; EAX z.B. nicht. Und zumindest bei AMD64 gibt es noch mehr Register um deren Sicherung sich der Aufrufer kümmern muss.

[edit]
Zitat von: i386 ABI
Registers %ebp, %ebx, %edi, %esi, and %esp ‘‘belong’’ to the cal-
ling function. In other words, a called function must preserve these registers’
values for its caller. Remaining registers ‘‘belong’’ to the called function. If a cal-
ling function wants to preserve such a register value across a function call, it must
save the value in its local stack frame.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 01. April 2012, 19:37
Naja, wenn der Handler leer ist
( (Klammer Auf) int_handler_0x21:
    iret
) (Kalmmer zu)
dann kommt die Exeption trotzdem
Titel: Re: Tastaturtreiber
Beitrag von: nnosdev am 03. April 2012, 21:16
Hi,

das hier ist keine Antwort sondern eine Frage.

Und zwar.. ich hab meine Interrupt Service Routinen geschrieben und soweit funktioniert das auch.
Wenn ich jetzt eine Taste drücke, dann empfange ich diesen Interrupt nur ein einziges Mal.
Jeder weitere Tastendruck wird dann nicht mehr verarbeitet (IRQ 0 wird jedoch permanent weiter
bearbeitet).

void isr_handler(cpu_state_t status)
{
if(status.int_no <= 0x1F) {
dprint("[ISR] Exception captured. Kernel stopped.");

while(1) {
// Stop CPU
asm volatile ("cli; hlt");
}
}else if (status.int_no >= 0x20 && status.int_no <= 0x2f) {

dprint("[ISR] Hardware interrupt received");

    if (status.int_no >= 0x28) {
        outb(0xA0, 0x20);
    }

    outb(0x20, 0x20); // EOI
}

dprint("[ISR] Received (but unhandled) interrupt: 0x%X", status.int_no);
}

Hat jemand eine Ahnung woran das liegen könnte?
Titel: Re: Tastaturtreiber
Beitrag von: Jidder am 03. April 2012, 21:39
Du musst den Scancode mit inb(0x60) lesen, um den Tastaturpuffer zu leeren.
Titel: Re: Tastaturtreiber
Beitrag von: nnosdev am 03. April 2012, 21:53
Danke :D

Titel: Re: Tastaturtreiber
Beitrag von: micha am 04. April 2012, 15:59
Hier mal mein Quälcode :wink: (http://forum.lowlevel.eu/index.php?topic=3011.0 (http://forum.lowlevel.eu/index.php?topic=3011.0))
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 04. April 2012, 18:28
Wie baust du den Kernel? Das mal zu testen zu können würde vermutlich schneller zu Erfolg führen als nur den Quellcode an zu sehen.

Was mir so aufgefallen ist:
cpu.S:
  push-/pop_cpu: rufst du zwar nirgends auf, aber das Funktioniert so natürlich nicht. als Makro würde schon eher gehen.

irq/handler.S:
  irq_handler0x21: ist weder leer, noch werden die Register ordnungsgemäß wieder hergestellt.

syscall:
  int_handler0x30: ignoriert den rückgabe wert von syscall

testhandler:
  das geht so nicht, einfach asm("iret") in ne C-Funktion reinhauen. Guck dir mal `objdum -d testhandler.o` an. Da siehst du dass der stack erst noch dem iret, mit leave wieder aufgeräumt wird.

[Edit]
sprintfr:
  du legst nirgends einen puffer für dein rückgabe string an! du verwendest rs uninitialisiert. das ist pures Glück wenn das mal gut geht.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 04. April 2012, 19:35
irq/handler.S:
  irq_handler0x21: ist weder leer, noch werden die Register ordnungsgemäß wieder hergestellt.
Das war ja auch nur zum rumprobieren..

syscall:
  int_handler0x30: ignoriert den rückgabe wert von syscall
Das ist ja noch garni fertig

testhandler:
  das geht so nicht, einfach asm("iret") in ne C-Funktion reinhauen. Guck dir mal `objdum -d testhandler.o` an. Da siehst du dass der stack erst noch dem iret, mit leave wieder aufgeräumt wird.
Da hab ich auch bloß probiert (ich probiere gern  :wink:; vergessen wieder raußzunehmen)

sprintfr:
  du legst nirgends einen puffer für dein rückgabe string an! du verwendest rs uninitialisiert. das ist pures Glück wenn das mal gut geht.
Eingentlich ging das immer
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 12:04
Wie baust du den Kernel? Das mal zu testen zu können würde vermutlich schneller zu Erfolg führen als nur den Quellcode an zu sehen.
src/kernel/Makefile
SRCS = $(shell find -name '*.[cS]')
OBJS = $(addsuffix .o,$(basename $(SRCS)))
CC = gcc
LD = ld

SRC = ..
KERNELSRC = .
IMGSRC = ../../img
KERNEL = $(IMGSRC)/sys/kernel/kernel

INC = -I $(SRC)/include
KERNINC = -I $(KERNELSRC)/include

ASFLAGS = -m32 $(INC)
CFLAGS = -m32 -Wall -fno-stack-protector -nostdinc $(INC)
LDFLAGS = -melf_i386 -Ttext=0x100000

KERNELCF = $(CFLAGS) $(KERNINC)
KERNELASF= $(ASFLAGS) $(KERNINC)

pseudolink: $(OBJS)
#Kernel kompiliert.

%.o: %.c
$(CC) $(KERNELCF) -c -o $@ $^
%.o: %.S
$(CC) $(KERNELASF) -c -o $@ $^
clean:
rm $(OBJS)
.PHONY: clean

Makefile
SRC = ./src
KERNELSRC = $(SRC)/kernel

SRCS = $(shell find -name '*.[cS]')
OBJS = $(addsuffix .o,$(basename $(SRCS)))
CC = gcc
LD = ld

INC = -I $(SRC)/include

IMGSRC = ./img
KERNEL = $(IMGSRC)/sys/kernel/kernel
IMGNAME= OrangePalm0-0-1winterBeta3

ASFLAGS = -m32 $(INC)
CFLAGS = -m32 -Wall -fno-stack-protector -nostdinc $(INC)
LDFLAGS = -melf_i386 -Ttext=0x100000

$(KERNEL): $(OBJS)
$(LD) $(LDFLAGS) -o $@ $^

iso-img:
mkisofs -R -b boot/grub/stage2_eltorito -no-emul-boot -boot-load-size 4 -boot-info-table -o $(IMGNAME).iso $(IMGSRC)
start-iso-qemu:
qemu -d int -cdrom $(IMGNAME).iso
print-src:
echo $(shell find -name '*.[chS]')

clean:
rm $(OBJS)
.PHONY: clean

mkall
# Kernel kompiliern
cd src/kernel
make
cd ../..
# Rest kompilieren & linken
make
# iso-image erstellen
make iso-img
# iso-image mit qemu starten
make start-iso-qemu
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 05. April 2012, 14:57
Du hast 16-Bit Interrupt Desptoren angelegt.

diff --git a/src/kernel/interrupt/idt.c b/src/kernel/interrupt/idt.c
--- a/src/kernel/interrupt/idt.c
+++ b/src/kernel/interrupt/idt.c
@@ -21,6 +21,7 @@ static void set_interrupt(int i, uint32_
   //obere 32-Bit
   idt[i] |=(
        ( type << 8 )   |
+       ( 1 << 11) |
        ( (dpl&3) << 13 )   |
        ( (present&1) << 15)|
        ( offset & 0xffff0000 )

Ich würde dir übrigens raten sämtliche Compiler-Warnungen  auszumerzen. Dein set_gdt_entry z.B. enthält nen fehler auf den du sogar hingewiesen wirst.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 15:29
Du hast 16-Bit Interrupt Desptoren angelegt.
Was hab ich da falsch gemacht? Wie mach ich's richtig?

Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 05. April 2012, 15:33
Du hast 16-Bit Interrupt Desptoren angelegt.
Was hab ich da falsch gemacht? Wie mach ich's richtig?

Du hast vergessen das Flag für 32-Bit Descriptoren zu setzen.

Füge die mit '+' gekennzeichnete Zeile in deinen Code ein.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 15:55
Ich hab jetzt die zeile eingefügt
( 0x800 ) | // 1 << 11nur leider geht es immernoch nicht :-(

Liegt der Fehler in der GDT? Es kommt ja ein GPF und es werden Segmente übergeben (als Errorcode), die ich garnicht hab!
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 05. April 2012, 16:13
Also die Zeile ist bei mir im Moment der einzige Unterschied zu dem von dir hochgeladenen Code. Und es gibt kein GPF.

Stimmt jetzt wenigsten dein eigener CPU dump mit dem von QEMU überein?
Deine GDT ist zwar falsch(64bit segmente im Protected mode), aber wenn QEMU das stören würde müsste es schon beim neuladen der Segmentregister meckern.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 16:19
Also EAX,EBX,ECX und EDX stimmen überein. Nur die anderen (ESP,CS...) nicht.
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 05. April 2012, 16:39
Die sollten jetzt auch übereinstimmen. Testest eventuell noch die alte Version? ('make clean')
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 16:46
Jetzt wird qemu nach init_idt schwarz :|
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 16:52
komisch.. :| mit deinem iso gehts
Titel: Re: Tastaturtreiber
Beitrag von: MNemo am 05. April 2012, 17:37
Jetzt wird qemu nach init_idt schwarz :|

Dann hast du wohl noch andere Änderungen gemacht. Versuch es doch mal mit dem Quellcode den du hier hochgeladen hast.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 17:45
Super!!!!! mit dem gehts :-) :-) :-D
Titel: Re: Tastaturtreiber
Beitrag von: micha am 05. April 2012, 20:49
Jetzt komme ich dem Tastaturtreiber schon näher.
Wenn ich einen Befehl an die Tasratur sende, wird der IRQ 0x21 ausgelöst. Ist das richtig?

Außerdem wird bei Tastendruck kein Interrupt ausgelöst.
Titel: Re: Tastaturtreiber
Beitrag von: micha am 07. April 2012, 12:59
OK. es geht  :lol: :lol:
Ich hab vergessen in init ein while(1); zu setzten nach init wird ja der prozessor angehalten  :-)

Danke für die Hilfe