Autor Thema: Tastaturtreiber  (Gelesen 18060 mal)

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« 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

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 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.
Dieser Text wird unter jedem Beitrag angezeigt.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #2 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ß

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 21. March 2012, 16:26 »
ld != objdump
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #4 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?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #5 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.
Dieser Text wird unter jedem Beitrag angezeigt.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #6 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?

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 21. March 2012, 21:36 »
Pastebin

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 22. March 2012, 13:36 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #9 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.
« Letzte Änderung: 22. March 2012, 23:56 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #10 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)

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 23. March 2012, 15:43 »
Wenn das:
Zitat
001014fd
EIP sein soll, dann steht da ein nop.
Es steht nach call outb

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #12 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.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 23. March 2012, 16:56 »
Dann vertehe ich nicht, warum dann ein GPF ausgelöst wird und nicht mein irq handler.
?????

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 23. March 2012, 17:08 »
Folgt auf den Tastaturinterrupt eventuell noch ein weiterer Interrupt?
Dieser Text wird unter jedem Beitrag angezeigt.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #15 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ß

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #16 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?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 28. March 2012, 16:50 »
Ich denke, dass die Einträge in der IDT nicht korrekt sind.
Dieser Text wird unter jedem Beitrag angezeigt.

micha

  • Beiträge: 141
    • Profil anzeigen
Gespeichert
« Antwort #18 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 ---- */

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 28. March 2012, 17:35 »
Entschuldige die vielleicht blöde Frage, aber wie ist IDT_ENTRIES definiert?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

 

Einloggen