Autor Thema: Problem bei Physikalischer Speicherverwaltung (Bitmap)  (Gelesen 26297 mal)

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #20 am: 21. November 2014, 20:18 »
Sieht richtig aus.

Weil du mit Integern rechnest und / deswegen eine ganzzahlige Division ist, kannst du auch direkt page_nummer / 32 machen. Der Rest, den du vor der Division abziehst, sind am Ende nur Nachkommastellen, die sowieso abgeschnitten werden.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #21 am: 21. November 2014, 21:26 »
Ok, dann passt das, eine kleine Frage hab ich noch bei der Initialisierung der Bitmap habe ich im Tutorial etwa folgenden Code: (nur mal ein kleiner Ausschnitt):


uintptr_t addr = (uintptr_t) &kernel_start;
while (addr < (uintptr_t) &kernel_end) {
    pmm_mark_used((void*) addr);
    addr += 0x1000;
}

Da ich uintptr_t nirgends als Typ definiert habe, dachte ich mir da könnte man doch auch einfach einen Typlosen pointer also (void*) nehmen? Irgendwie funktioniert das aber nicht ganz so wie ich mir das vorgestellt habe... Ich kann ja z.B. uint8_t durch ein einfaches "unsigned char" ersetzen, oder ein uint16_t durch ein unsigned short, durch was muss  ich dann uintptr_t ersetzen, wenn es mit "void*" nicht funktioniert?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #22 am: 21. November 2014, 22:05 »
uintptr_t ist ein Integer-Datentyp, der so breit ist wie ein Pointer. Das sind auf i386 32 Bit und auf x86_64 64 Bit, also das, was normalerweise ein unsigned long darstellen kann. So würde ich den Typ dann auch definieren.

Ein Pointer zeigt aber immer auf virtuellen Speicher. Das heißt, uintptr_t (und void*) sind geeignet, um Adressen im virtuellen Adressraum zu referenzieren. Wenn man es genau nimmt, ist der physische Adressraum etwas anderes und du könntest dafür separate Typen benutzen, um die Absicht klar zu machen. tyndur hat zum Beispiel einen paddr_t für physische Adressen (der auch wieder ein unsigned long ist). Aber unabhängig davon, ob du paddr_t oder uintptr_t nimmst: Pointertypen wie void* für physischen Speicher würde ich nie benutzen, denn beim Dereferenzieren käme nichts sinnvolles heraus.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #23 am: 21. November 2014, 22:08 »
Bedeutet das quasi ich kann einfach jedes "uintptr_t" durch ein "unsigned long" austauschen?

Entschuldige die Frage aber was bedeutet "Dereferenzieren"? Denn genau da krige ich im Moment ne Fehlermeldung.


kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #24 am: 21. November 2014, 22:57 »
Dereferenzieren heißt auf die Speicher zuzugreifen, auf den ein Pointer zeigt. Also *p dereferenziert p.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #25 am: 21. November 2014, 23:04 »
Achso ok dann hab ich das verstanden. Danke

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #26 am: 22. November 2014, 14:22 »
Nur eine kleine Frage zur Definition von "NULL", NULL ist ja nicht gleich 0 oder?, d.h. ich muss NULL irgendwie definieren, da ich es sonst nicht benutzen kann. Wie genau sollte ich NULL definieren.

wenn ich #define NULL   0 mache, dann kann ich ja auch gleich 0 schreiben.

Oder sehe ich das falsch?

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #27 am: 22. November 2014, 15:21 »
Hallo,
ich habe bei NULL folgendermassen definiert:
#define NULL ((void*)0)
Viele Grüsse
OsDevNewbie

Ein Computer ohne Betriebsystem ist nicht mehr wert als ein Haufen Schrott.
Ein Computer ist eine Maschine, die einem Lebewesen das kostbarste klaut, was sie selber nicht hat:
DIE ZEIT DES LEBENS

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #28 am: 22. November 2014, 15:28 »
ok danke :DD

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #29 am: 22. November 2014, 15:52 »
Die Typen uint32_t, int8_t, uintptr_t usw. haben ihren Sinn. Wenn du eine bestimmte Bitbreite brauchst, dann solltest du diese Typen benutzen, und nicht "unsigned long", auch wenn das zufällig die gleichen Typen sind. Aus dem gleichen Grund solltest du diese Typen auch nicht selbst definieren (gilt auch für NULL).

Dein Compiler stellt dir das alles in den Header-Dateien stdint.h und stddef.h bereit. Nutze sie. Die sind auch für Kernelprogrammierung geeignet und enthalten noch ein paar andere nützliche Dinge.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #30 am: 22. November 2014, 16:23 »
oh ok danke dann werd ich mal meine eigenen mit denen des compilers austauschen...

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #31 am: 22. November 2014, 16:28 »
blöde frage, aber wenn ich versuche die Datei mit #include <stdint.h> einzubinden, bekomme ich einen Kompilierungsfeher dass die Datei nicht gefundne wurde.

was mache ich falsch?

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #32 am: 22. November 2014, 17:35 »
außerdem geht mein multitasking versuch irgendwie drunter und drüber... ich hbe 3 Tasks und habe das TSS und die schedule sowie die init_task Funktion wie im Tutorial aufgesetzt. Nur endet mein Kernel immer mit einer Invalid Opcode Exception, und irgendiwe werde ich nicht ganz schlau daraus...

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #33 am: 22. November 2014, 19:33 »
blöde frage, aber wenn ich versuche die Datei mit #include <stdint.h> einzubinden, bekomme ich einen Kompilierungsfeher dass die Datei nicht gefundne wurde.
Vermutlich kompilierst du mit ungünstigen Compiler-Flags. Wenn da "-nostdinc" drin steht, dann ersetze das mal durch "-ffreestanding".

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #34 am: 23. November 2014, 09:17 »
Ja danke, jetz hats geklappt. Allerdings funktioniert mein Hardware Multitasking immer noch nicht... Ich registrieren 3 Tasks von denen immernur der letzte läuft und dann beim ersten Timerinterrupt bekomme ich eine invalid opcode exception...

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #35 am: 23. November 2014, 14:19 »
ok jetzt hab ich ein bisschen unbedeutenden code verändert, ein par debugging ausgaben... und jetz kriege ich statt der Invalid Opcode Exception einen General Protection Fault...

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #36 am: 23. November 2014, 15:13 »
Also um dir zu helfen, brauchen wir mehr Informationen. Einmal ist der Quellcode interessant, falls du den irgendwo auf github oder einem anderen Repository hochladen könntest, wäre das am einfachsten für uns da reinzuschauen. Außerdem solltest du dich mit den Logging-Funktionen deines Emulators auseinandersetzen. Zum Beispiel hab ich das vor einiger Zeit mal hier an einem konkreten Problem erklärt: http://forum.lowlevel.eu/index.php?topic=3247.msg37696#msg37696
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #37 am: 23. November 2014, 16:50 »
Also das mit dem Quellcode ist eher schwierig weils ziemlich viel ist an dem es liegen könnte, aber ich kann den relevanten Teil mal hier hochladen, die Logging Funktion meines Emulators kann ich leider nicht nutzen, weil ich einen echten PC als Emulator verwende und von einem USB-Stick boote (Die quemu installation ist desöfteren gescheitert und ein ordentliches Image hab ich dank fehlendem grub legacy auch nicht hingekriegt).

Aber ich habe es jetz hinreichend getestet, also wenn nur ein Task läuft ist alles in Ordnung, aber sobald ich mehrere tasks laufen habe, eigtl immer genau dann wenn der Taskswitch stattfindet, also beim Timerinterrupt, bekomme ich einen General Protection Fault, der von meinem Interrupt Handler bearbeitet wird und dann hält mein Kernel gewollt an.

Anbei meine task.c:

// Sourcecode File for Headerdatei task.h
#include "console.h"
#include "pmm.h"
#include "task.h"
//#include "stdint.h"
#include <stdint.h>
#include <stddef.h>

struct task {
    struct cpu_state* cpu_state; // Pointer auf obige Struktur
    struct task*      next;
};

static struct task* first_task = NULL; // Nullzeiger
static struct task* current_task = NULL; // Nullzeiger

// Jeder Task: Einsprungpunkt -> entry; Stack -> stack;

struct task* init_task(void* entry)
{

    uint8_t* stack = pmm_alloc(); // unsigned char (uint8_t*) weil void* typlos
    uint8_t* user_stack = pmm_alloc(); // -"-


    // CPU-Zustand fuer den neuen Task festlegen
    struct cpu_state new_state = {
        .eax = 0,
        .ebx = 0,
        .ecx = 0,
        .edx = 0,
        .esi = 0,
        .edi = 0,
        .ebp = 0,
        .esp = (uint32_t) user_stack + 4096, // Ring Wechsel auf Ring 3
        .eip = (uint32_t) entry,

        // Ring-0-Segmentregister : 0x08
        .cs  = 0x1b,
        .ss  = 0x20 | 0x03, // benutzt weil Ringwechsel auf 3

        // IRQs einschalten (IF = 1)
        .eflags = 0x202,
    };


    /*
     * Den angelegten CPU-Zustand auf den Stack des Tasks kopieren, damit es am
     * Ende so aussieht als waere der Task durch einen Interrupt unterbrochen
     * worden. So kann man dem Interrupthandler den neuen Task unterschieben
     * und er stellt einfach den neuen Prozessorzustand "wieder her".
     */
     struct cpu_state* state = (void*) (stack + 4096 - sizeof(new_state));
    *state = new_state;

    /*
     * Neue Taskstruktur anlegen und in die Liste einhaengen
     */

   
    struct task* task = pmm_alloc();
    task->cpu_state = state;
    task->next = first_task;
    first_task = task;
    return task;
}

// Aktueller Zustand wird als Parameteuebergeben und gespeichert.
// Neuer Prozessorzusatand wirdurueck gegeben

struct cpu_state* schedule(struct cpu_state* cpu)
{

// Wenn Task vorhanden, Zusatand sichern. Wenn nicht Prozessorzustand vernachla$
  if (current_task != NULL) {
    current_task->cpu_state = cpu;
  }

  // Naechsten Task auswaehlen -> schleife von vorne wenn durch
  if (current_task == NULL) {
    current_task = first_task;
  }
  else {
    current_task = current_task->next;
    if (current_task == NULL) {
       current_task = first_task;
    }
  }

  // Prozessorzustand des neuen Task zurueckgeben
  cpu = current_task->cpu_state;

  return cpu;

}


Und hier mal mein Interrupt Handler:

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 Kernel angehalten! \n");
        // Hier den CPU-Zustand ausgeben

        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) {
            kputs("Timerinterrupt vor");
            new_cpu = schedule(cpu); // #debug
            set_tss_entry(1, (unsigned long) (new_cpu + 1)); // #debug
            kputs("Timerinterrupt nach");
           }

           if (cpu->intr == 0x21) {
            kputs("Tastaturinterrupt");
           }

           if (cpu->intr >= 0x28) {
               outb(0xa0, 0x20); // End of Interrupt: Slave PIC
            }

            outb(0x20, 0x20); // End of Interrupt: Master PIC
        }
   }
return new_cpu;
}


Die Funktion set_tss_entry erstellt einen Eintrag im TSS das in einer anderen Datei liegt. Diese Funktion wird über eine Headerdatei bereitgestellt und funktioniert auch.
Die kputs() im Timerinterrupt sind nur zu Debuggingzwecken vorhanden.

Vg s137
« Letzte Änderung: 23. November 2014, 16:53 von s137 »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #38 am: 23. November 2014, 19:00 »
Also das mit dem Quellcode ist eher schwierig weils ziemlich viel ist an dem es liegen könnte, aber ich kann den relevanten Teil mal hier hochladen
Gerade weil es an so vielem liegen kann, ist der komplette Quelltext hilfreich. An dem geposteten Code kann ich nichts falsches entdecken.

die Logging Funktion meines Emulators kann ich leider nicht nutzen, weil ich einen echten PC als Emulator verwende und von einem USB-Stick boote (Die quemu installation ist desöfteren gescheitert und ein ordentliches Image hab ich dank fehlendem grub legacy auch nicht hingekriegt).
Das ist nicht gut. Gerade am Anfang ist ein Emulator sehr nützlich.

Aber ich habe es jetz hinreichend getestet, also wenn nur ein Task läuft ist alles in Ordnung, aber sobald ich mehrere tasks laufen habe, eigtl immer genau dann wenn der Taskswitch stattfindet, also beim Timerinterrupt, bekomme ich einen General Protection Fault, der von meinem Interrupt Handler bearbeitet wird und dann hält mein Kernel gewollt an.
Wie lautet der Fehlercode?
Dieser Text wird unter jedem Beitrag angezeigt.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #39 am: 23. November 2014, 19:12 »
Zitat
Wie lautet der Fehlercode?
Der Fehlercode also die Nummer des Interrupts "cpu->intr" ist 13 was meiner Belegung nach einem General Protection Fault entspricht.

Zitat
Das ist nicht gut. Gerade am Anfang ist ein Emulator sehr nützlich.
Das mit dem Emulator könnte auf meinem System schwierig werden, aber ich kanns ja nochmal versuchen...

Zitat
Gerade weil es an so vielem liegen kann, ist der komplette Quelltext hilfreich. An dem geposteten Code kann ich nichts falsches entdecken.
dann werde ich mal schauen ob ich mein projekt irgendwie auf github bekomme...
sollte ja nicht so schwer sein... aber eigtl sollte ja nur der code den ich gepostet habe für mein problem releavant sein... oder? kann es daran liegen dass meine physische Speicherverwaltung nicht richtig funktioniert und die pmm_alloc() Funktion nicht funktioniert?
« Letzte Änderung: 23. November 2014, 19:17 von s137 »

 

Einloggen