Autor Thema: [C++] OS hängt sich beim Laden der GDT aud  (Gelesen 6427 mal)

Niklas

  • Beiträge: 3
    • Profil anzeigen
Gespeichert
« am: 18. February 2013, 20:36 »
Hallo zusammen,
Ich schreibe grade mithilfe des in der Wiki stehenden OS-Dev-Tutorials und Brans Kernel Tutorial einen kleinen C++-Kernel. Allerdings hängt sich dieser bei dem Laden der GDT auf. Ich bekomme keinen Compilerfehler, denke aber, dass der Fehler irgendwo bei dem erstellen oder laden des Zeigers auf die GDT leigen muss.
Mein Code:
void CGDT::AddEntry(int iEntry,
               uint32_t iBase,
               uint32_t iLimit,
               int iFlags)
{
   m_aGDT[iEntry]  = iLimit & 0xffffLL;
   m_aGDT[iEntry] |= (iBase & 0xffffffLL) << 16;
   m_aGDT[iEntry] |= (iFlags & 0xffLL) << 40;
   m_aGDT[iEntry] |= ((iLimit >> 16) & 0xfLL) << 48;
   m_aGDT[iEntry] |= ((iFlags >> & 0xffLL) << 52;
   m_aGDT[iEntry] |= ((iBase >> 24) & 0xffLL) << 56;
}

void CGDT::Init()
{   
   // First Entry is NULL
   AddEntry(0, 0, 0, 0);
   
   AddEntry(1, 0, 0xFFFFF,
          GDT_FLAG_SEGMENT | GDT_GRAN_32_BIT |
          GDT_FLAG_CODESEG | GDT_GRAN_4K_GRAN |
          GDT_FLAG_PRESENT);
         
   AddEntry(2, 0, 0xFFFFF,
          GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG |
          GDT_FLAG_PRESENT |
          GDT_GRAN_4K_GRAN | GDT_GRAN_32_BIT);
         
   AddEntry(3, 0, 0xFFFFF,
          GDT_FLAG_SEGMENT | GDT_FLAG_CODESEG |
          GDT_FLAG_PRESENT | GDT_FLAG_RING3 |
          GDT_GRAN_4K_GRAN | GDT_GRAN_32_BIT);
         
   AddEntry(4, 0, 0xFFFFF,
          GDT_FLAG_SEGMENT | GDT_FLAG_DATASEG |
          GDT_FLAG_PRESENT | GDT_FLAG_RING3 |
          GDT_GRAN_4K_GRAN | GDT_GRAN_32_BIT);
         
   // Write in GDT
   struct {
      uint16_t limit;
      void* pointer;
   } PACKED gdtp = {
      GDT_ENTRIES * 8 - 1,
      m_aGDT
   };
               
   asm volatile("lgdt %0" : : "m" (gdtp));
   asm("mov $0x10, %ax;"
      "mov %ax, %ds;"
      "mov %ax, %es;"
      "mov %ax, %fs;"
      "mov %ax, %gs;"
      "mov %ax, %ss;");
}
Ich bin mir vor allem unsicher, ob ich den Zeiger auf die GDT mit dem struct richtig erzeuge.

Ich hoffe, das mir jemand helfen kann.
Danke schonmal im Vorraus.
Niklas

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 18. February 2013, 20:58 »
Als erstes solltest du herausfinden, wo der Fehler wirklich genau auftritt. Du kannst dazu qemu -d int benutzen, das die Debug-Log für Interrupts (einschließlich Exceptions) aktiviert. Wenn der Kernel hängt, schließt du qemu und schaust in /tmp/qemu.log nach dem CPU-Dump nach der Zeile mit v=0d (Exception 0x0d = 13 = General Protection Fault (#GP)). Dort findest du auch den Wert für den Instruktionspointer eip. Den kannst du wiederum einer Codezeile in deinem Kernel zuordnen, wenn du den Kernel mit objdump disassemblierst.

Der GDT-Zeiger sieht auf den ersten Blick richtig aus, falls dein PACKED das tut, was es verspricht.
« Letzte Änderung: 18. February 2013, 21:01 von kevin »
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 18. February 2013, 21:09 »
Gdb is auch ne coole Sache, ist im Englischen Forum weiter verbreitet(habs auch noch nicht umgesetzt steht aber weit obenauf meiner Todo Liste)http://wiki.osdev.org/GDB du fügst so eine Datei gdb_stub.c erstellen und damit in deinem Code sog Breakpoints setzen dann kannst du hie und da sog. Breakpoints setzen und die Datei mit gdb blablabla-kernel.elf debuggen und iwie die Breakpoints durchgehen und mit examine und info Registerinhalte und Memorystellen zu diesem Zeitpunkt ausmachen ich glaub man kann man kann sich auch Stack Backtraces ausliefern lassen.

Wie gesagt ich habs selbst nicht ausprobiert  :oops: aber es muss total cool sein.

Man brauch aber serielle Konsole.
« Letzte Änderung: 18. February 2013, 21:13 von Martin Erhardt »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 18. February 2013, 21:11 »
gdb ist grundsätzlich ein nützliches Werkzeug, aber für diesen Fall eher nicht. Wo würdest du denn Breakpoints setzen wollen? Einfach abstürzen lassen und den CPU-Dump bei der Exception anschauen ist in so einem Fall viel leichter.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 18. February 2013, 21:14 »
gdb ist grundsätzlich ein nützliches Werkzeug, aber für diesen Fall eher nicht. Wo würdest du denn Breakpoints setzen wollen? Einfach abstürzen lassen und den CPU-Dump bei der Exception anschauen ist in so einem Fall viel leichter.
stimmt aber immer wenn ich sehe, dass was iwo nicht geht ärger ich mich das ichs immer noch nich hab :(

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 18. February 2013, 21:57 »
GDB-Stubs in deinem OS implementieren brauchst du nur, wenn du an einem echten PC z.B. über die serielle Schnittstelle debuggen willst. qemu und bochs haben einen eingebauten GDB-Stub, den musst du einfach nur benutzen (siehe auch Debugging im Wiki).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

Niklas

  • Beiträge: 3
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 19. February 2013, 13:32 »
Danke erstmal für die vielen und schnellen Antworten.
Der Kernel hängt sich nach dem neuladen des letzten Registers (mov %ax, %ss) auf. wenn ich diese Zeile auskommentiere, tritt der Fehler in der Zeile davor (mov %ax, %gs) auf.
Ich kann mir darazus allerdings momentan keinen reim bilden...

Martin Erhardt

  • Beiträge: 165
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 19. February 2013, 16:50 »
Moin Niklas,
Ich bin mir relativ sicher deinen Fehler gefunden zu haben; In AT&T ASM Syntax werden die einzelnen Asm Instruktionen nicht mit einem Semilkon abgeschlossen.
Bloß der gesamte ASM inline aufruf in C wird mit einem Semilkon abgeschlossen(wie man z.b. hier in den Beispielen sieht: http://www.lowlevel.eu/wiki/Teil_2_-_Assembler_101)
(Es kann sinnvoll sein dem Forum mitzuteilen ob es sich um einen Syntax oder Laufzeitfehler handelt, bei letzterem hilft nämlich kein Debugging sondern besser C oder ASM lernen ;) )
« Letzte Änderung: 19. February 2013, 16:57 von Martin Erhardt »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 19. February 2013, 17:28 »
In der Zeile m_aGDT[iEntry] |= ((iFlags >> & 0xffLL) << 52; fehlt etwas hinter dem >>. Ich nehme an, dass da was beim Kopieren flöten gegangen ist. Wie sieht das Original aus? Wie sind die Konstanten definiert? Ist m_aGDT ein Array? Ist es eine Membervariable? Wenn ja, wie wird die Klasse instanziiert? Bist du dir sicher, dass deine Kernelumgebung ausreichend für C++-Code eingerichtet ist? Gerade globale Variablen und deren Konstruktoren können problematisch sein und zu undurchschaubaren Bugs führen, wenn nicht alles funktioniert.
« Letzte Änderung: 19. February 2013, 17:31 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

Niklas

  • Beiträge: 3
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 19. February 2013, 19:40 »
Ich habe meinen Fehler gefunden:
Ich habe bei die Definition meiner Flags für die Segmentgröße und breite eine 0 vergessen (0x80 statt 0x800).
In diesem Sinne nochmal vielen Dank an alle, die mir geholfen haben.

Niklas

 

Einloggen