Autor Thema: Qemu = ok, echt Hardware = Auaa... ;(  (Gelesen 37266 mal)

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« am: 12. January 2014, 17:30 »
Hallo,

nachdem ich einige Treiber programmiert habe und mich aktuell mit dem Thema Paging rumschlage wirft mich der Kernel beim Betrieb auf echter Hardware wieder um einiges zurück.

Mein Kernel hat den Grundaufbau des Tutorial stark beibehalten, jedefalls wenn es um Sachen wie GTD, IVT, Task & Schudule geht.

Und hier liegt auch das Problem! Mein Kernel läuft wunderbar auf Qemu. Manschmal bleibt er beim PMM stehen aber liegt wohl am Qemu, denn bei neustart läuft er weiter. Auf ECHTER Hardware (getestet mit 3 underschiedlichen PC's) passiert folgendes:
- Bootloader wird geladen (GRUB4DOS)
- Grub läd den Kernel
- Kernel läuft
- Erster Task wird gestartet => CPU restet!

=> Vermutlich Triple Fault

Jetzt habe ich alle möglich "hlt" gesetzt, mit print Fehler ausgegeben,etc.
Am Anfang dachte ich, es hat etwas mit der IVT zutun und dem Hardware-Interrupt Timer. Dann vermutete ich den Fehler in den Software Interrupts, da ohne Task der Kernel weiterläuft und testweise mir bei jedem Timer-Interrupt "TIMER!" auf dem Bildschirm schreibt!

Also auszuschließen ist:
- Debug mit Exeption, da sofort CPU-Reset
- Fehler in der IVT
- Fehlerfunktion Software-Interrupts
- fehlerhafte Behandlung von Hardware-Interrupts
- Da bleibt nur noch der Schedule!

Und siehe da der Kernel läuft ohne Schedule (& ohne Task!) ganz normal. Da der orginal Schedule des Tutorial nicht viele Parameter verändern und auch alles korrekt zu sein scheit, liegt es vielleicht an der Datei int_stub.S die in ASM geschrieben ist.
Allerdings konnte ich dort kein Fehler feststellen und er bricht auch nicht ab. ERST wenn der Zustand wiederhergestellt wird, beim Befehl "iret" <<<=== Es funktioniert aber ohne Task (&Schedule)!

Meine letzte Vermutung ist, dass im Befehl init_gdt() irgendwas schief läuft & deswegen für Task irgendwas an Segmenten falsch gesetzt ist. Durch die GDT steig ich allerdings nicht wirklich durch. Und meine ist auch noch orginal getreu wie im Tutorial und läuft unter Qemu ja auch super, aber unter echter Hardware leider nicht!

Hat jemand eine Idee wie das Problem zu lösen oder zumindest Erklärbar wäre?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 12. January 2014, 17:57 »
Manschmal bleibt er beim PMM stehen aber liegt wohl am Qemu, denn bei neustart läuft er weiter.
Das wäre mein erster Ansatzpunkt für das Problem. Ein Unterschied zwischen echter Maschine und Qemu sind Details des Speicherlayouts und die Belegung des Speichers durch Datenstrukturen (z.B. Multiboot-Header). Wenn die Speicherverwaltung in QEMU komische Sachen macht, dann könnte sie auf der echten Maschine noch mehr Probleme machen. Ich würde einmal versuchen herauszufinden, warum sie in QEMU nicht zuverlässig funktioniert, und überprüfen, ob sie auf der echten Maschine funktioniert.
Dieser Text wird unter jedem Beitrag angezeigt.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 12. January 2014, 18:26 »
Hmm... Auf echter Hardware läuft der Speicher. Wie gesagt, der CPU-RESET kommt erst sobald ein Task ausgeführt wird, egal ob Multiboot-Module oder "virtueller Task" im Kernel.

Qemu bleib manschmal bei dem Befehl pmm_init() stehen. Das ist der erste Befehl im Kernel, danach wird das Paging aktiviert. Aber das hat bis jetzt noch nie Probleme auf echter Hardware gemacht.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #3 am: 14. January 2014, 14:37 »
Leider konnte ich den Fehler noch nicht finden. Jemand ne Idee ?

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 14. January 2014, 16:13 »
Also Qemu bleibt auch bei pmm_init() stehen, wenn ich weit hintem im Code den Timer setze.
Vermutlich kommt Qemu nicht so schnell mit der Ausgabe hinterher, als wie es den Code verarbeitet. Somit könnte es doch etwas mit der Speicherverwaltung zu tun haben, dass er manschmal ohne am Timer zu fummeln stehen bleibt. Evtl. auch Ursache für CPU-Reset bei echter Hardware!

Mein pmm_init():
void pmm_init(struct multiboot_info* mb_info)
{ /*  inititalisiert die Speicherverwaltung. Alle Speicherbereiche,
      die beim Start des Systems frei sind, müssen als frei markiert werden, der Rest als belegt.
  */     
    struct multiboot_mmap* mmap = mb_info->mbs_mmap_addr;
    struct multiboot_mmap* mmap_end = (void*)
        ((uintptr_t) mb_info->mbs_mmap_addr + mb_info->mbs_mmap_length);

    /* Per Default ist erst einmal alles reserviert */
    memset(bitmap, 0, sizeof(bitmap));

    /*
     * Nur, was die BIOS-Memory-Map als frei bezeichnet, wird wieder als frei
     * markiert
     */
    while (mmap < mmap_end) {
        if (mmap->type == 1) {
            /* Der Speicherbereich ist frei, entsprechend markieren */
            uintptr_t addr = mmap->base;
            uintptr_t end_addr = addr + mmap->length;

            while (addr < end_addr) {
                pmm_free((void*) addr);
                addr += 0x1000;
            }
        }
        mmap++;
    }

    /* Den Kernel wieder als belegt kennzeichnen */
    uintptr_t addr = (uintptr_t) &kernel_start;
    while (addr < (uintptr_t) &kernel_end) {
        pmm_mark_used((void*) addr);
        addr += 0x1000;
    }

    /*
     * Die Multibootstruktur auch, genauso wie die Liste von Multibootmodulen.
     * Wir gehen bei beiden davon aus, dass sie maximal 4k gross werden
     */
    struct multiboot_module* modules = mb_info->mbs_mods_addr;

    pmm_mark_used(mb_info);
    pmm_mark_used(modules);

    /* Und die Multibootmodule selber sind auch belegt */
    int i;
    for (i = 0; i < mb_info->mbs_mods_count; i++) {
        addr = modules[i].mod_start;
        while (addr < modules[i].mod_end) {
            pmm_mark_used((void*) addr);
            addr += 0x1000; //DEC: 4096 (4k)
        }
    }
}

Der Timer:
int counter = 1193182 / 100;// FREQUENZ
outb(0x43, 0x32);
outb(0x40, counter & 0xFF);
outb(0x40, counter >> 8);

Das zu noch kurz die Anmerkung, dass der eigentliche Fehler, wie im 1.Post beschieben vorher auftratt, bevor ich den Timer gesetzt habe. Ich habe nämlich zuvor die Standartfrequenz unverändern gelassen und einfach nur den IRQ0 bzw. 32 benutz! Das Problem, dass Qemu manschmal bei pmm_init(); (jedefalls laut Textausgabe!) stehen bleibt bestand dort aber auch.

Mit vmm_map_page() mappe ich in der Funktion vmm_init() die direkt nach pmm_init() aufgerufen wird die erst 8MB Speicher virtuell gleich physischer! Vielleicht liegt auch dort der Fehler.

Vielleicht hilft dieser Post etwas dem Problem auf das Bit zu kommen!

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #5 am: 23. January 2014, 15:02 »
Manschmal bleibt er beim PMM stehen aber liegt wohl am Qemu, denn bei neustart läuft er weiter.
Das wäre mein erster Ansatzpunkt für das Problem. Ein Unterschied zwischen echter Maschine und Qemu sind Details des Speicherlayouts und die Belegung des Speichers durch Datenstrukturen (z.B. Multiboot-Header). Wenn die Speicherverwaltung in QEMU komische Sachen macht, dann könnte sie auf der echten Maschine noch mehr Probleme machen. Ich würde einmal versuchen herauszufinden, warum sie in QEMU nicht zuverlässig funktioniert, und überprüfen, ob sie auf der echten Maschine funktioniert.

Wie finde ich herrauß wieso Qemu manschmal bei pmm_init() stehen bleibt?

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 23. January 2014, 15:33 »
Schwer zu sagen. Vielleicht indem du den Code mit ordentlich Debug-Ausgaben spickst.

Was bei mir deinem Code auffällt, ist dass du nicht prüfst, dass die Speicherbereiche auf ganze Seiten ausgerichtet sind. Adressen und Größen, die in der Multiboot-Info stehen, sind nicht unbedingt Vielfache von 4096 und du musst die Werte selbst ausrichten. Das kann auch auf kernel_start/_end zutreffen, je nach dem wie dein Linkerskript aussieht. Außerdem kann es sein, dass mmap->base und mmap->length größer als 2^32 (4 GB) sind und dann nicht mehr in ein uintptr_t passen. Du solltest vorher prüfen, ob die Werte größer sind und ggf. nur den Bereich unter 2^32 berücksichtigen.
Dieser Text wird unter jedem Beitrag angezeigt.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #7 am: 23. January 2014, 15:46 »
kernel_start & end Linker:

SECTIONS
{
 . = 0x100000; //Kernel an 1MB laden
 kernel_start = .;
 .text : {
     *(multiboot)
     *(.text)
  }
 .data ALIGN(4096) : {
     *(.data)
  }
 .rodata ALIGN(4096) : {
     *(.rodata)
  }
  .bss ALIGN(4096) : {
  *(.bss)
  }

. = ALIGN(4096);
kernel_end = .;


Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 23. January 2014, 16:38 »
Jo mit dem Linkerskript sollten kernel_start und kernel_end keine Probleme machen.
Dieser Text wird unter jedem Beitrag angezeigt.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 23. January 2014, 18:36 »
Außerdem habe ich jetzt mmap->base und mmap->length auf max. 4GB begrenzt.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 23. January 2014, 18:40 »
Und die Probleme bestehen leider immer noch! Zum testen auf echter Hardware lade ich noch nicht mal ein Modul, sondern nur den Kernel selbst.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 23. January 2014, 20:33 »
Also es muss doch ein Problem mit dem Paging vom Tutorial geben, dann wenn ich PG nicht aktiviere es nicht vom CPU-Reset kommt und es auch kein Anhalten von Qemu gibt!!!

Sobald PG aktiv ==>> CPU-RESET

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #12 am: 23. January 2014, 20:54 »
Jetzt gibt er mir eine Exception 14 aus.

Page Fault:
eip=1058309
ERROR:00000101

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 23. January 2014, 22:14 »
Also es muss doch ein Problem mit dem Paging vom Tutorial geben, dann wenn ich PG nicht aktiviere es nicht vom CPU-Reset kommt und es auch kein Anhalten von Qemu gibt!!!
Diese Schlussfolgerung ist nicht korrekt. Es kann auch woanders noch ein Problem geben. Ein nicht seltenes Szenario sind Fehler in der Speicherverwaltung, bei dem Speicherbereiche, die nicht verwendbar sind, als frei markiert werden, oder Speicherbereiche doppelt vergeben werden. Beide können zur Folge haben, dass in den Page Tables fehlerhafte Werte stehen und Page Faults entstehen. Um das nochmal zu betonen: Dieses Problem ist nicht die einzige mögliche Ursache.

Page Fault:
eip=1058309
ERROR:00000101

Vorschlag: Lass dir Adressen als Hexadezimalzahl ausgeben. Der Wert von EIP ist dann 0x102605. Außerdem solltest du das Register CR2 (Adresse, auf die versucht wurde zuzugreifen) auslesen. Damit kannst du dann nämlich auch was anfangen. Wenn CR2 gleich EIP ist, weißt du, dass die Ausführung des Codes selbst den Page Fault verursacht hat. Wenn sie ungleich sind, ist der Befehl an der Adresse in EIP ein Speicherzugriff. In beiden Fällen kann es manchmal interessant sein welche Funktion an dieser Adresse ist. Wenn du deinen Kernel disassemblierst (objdump -d kernel), solltest du an der Adresse 102605 die dazugehörige Funktion finden.

Der Fehlercode 00000101 sagt dir außerdem, dass es ein Zugriff von User Space aus war (zur Dekodierung dieses Wertes siehe Intel Manuals Volume 3, 4.7 Page Fault Exceptions).

Folgende Theorie: Du hast den letzten Absatz in diesem Abschnitt des Tutorials nicht gelesen: http://www.lowlevel.eu/wiki/Teil_9_-_Paging#Page_Directory_und_Page_Tables

Zitat
Mit diesem Code funktioniert unser Kernel jetzt wieder. Er bricht allerdings mit einer Exception 14 (einem Page Fault) ab: Das passiert, sobald er in einen Userspace-Task springen möchte. Bisher haben wir alle Pages nur für den Kernel gemappt. Man könnte jetzt natürlich hergehen und einfach das User-Flag setzen, dann funktionieren auch die Tasks wieder. Aber zukunftsfähig ist die Methode, einfach mal die ersten vier Megabytes zu mappen natürlich nicht.
Dieser Text wird unter jedem Beitrag angezeigt.

streetrunner

  • Beiträge: 67
    • Profil anzeigen
Gespeichert
« Antwort #14 am: 23. January 2014, 22:46 »
Zitat
(zur Dekodierung dieses Wertes siehe Intel Manuals Volume 3, 4.7 Page Fault Exceptions)
Oder hier: http://www.lowlevel.eu/wiki/Exception#Page_Fault

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 30. January 2014, 17:23 »
ok, ich habe etwas am PG gebastelt und das hat die Exeption ausgelöst. Ich habe nun den standart vom Tutorial hergestellt. Die Exeption ist zwar weg, das Problem mit dem CPU-Reset bleibt.

Qemu läuft zwar jetzt wieder aber es kommt ca. zwischen jedem 10ten und 15ten Startversuch zum Anhalten (ohne Exeption!) bei pmm_init() bzw. vmm_init().

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #16 am: 31. January 2014, 17:04 »
Vielleicht indem du den Code mit ordentlich Debug-Ausgaben spickst.

Diese habe ich auch Probiert und unter Qemu bleibt er bei diesem Codeabschnitt (pmm_init()) stehen:
while (mmap < mmap_end) {
 if (mmap->type == 1) {
uintptr_t addr = mmap->base;
uintptr_t end_addr = addr + mmap->length;

while (addr < end_addr) {
pmm_free ((void*) addr);
addr += 0x1000;
}
}
mmap++;
}


Vielleicht kann man damit etwas anfang...

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 31. January 2014, 17:23 »
Und jetzt bitte genauer suchen. :-) Wenn du weißt, wo genau es hängt, dann kriegst du vermutlich auch raus, warum dort hängt.
Ich würde mal auf pmm_free() tippen.

wissenshunger

  • Beiträge: 49
    • Profil anzeigen
Gespeichert
« Antwort #18 am: 01. February 2014, 15:52 »
void pmm_free(void* page)
{
 uintptr_t index = (uintptr_t) page / 4096;
 bitmap[index / 32] |= (1 << (index / 32));
}

Mehr steht da nicht drinnen.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 01. February 2014, 16:35 »
Und doch steckt da ein Fehler drin. Du willst da (1 << (index % 32)) haben. Sonst landet in der Bitmap nicht allzuviel freier Speicher^^
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

 

Einloggen