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

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #60 am: 25. November 2014, 13:57 »
Also laut dieser Seite: http://www.lowlevel.eu/wiki/Global_Descriptor_Table
siehe hier: "Ein Task State Segment für Multitasking (Present, Ring 3, 386-TSS)" sollte es doch in Ring 3 eingetragen werden, oder?


OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #61 am: 25. November 2014, 14:38 »
Also ich habe bei meinem Kernel die TSS als Ring 0 definiert. Kannst ja mal ausprobieren ob es funktioniert.
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 #62 am: 25. November 2014, 19:24 »
Also gut… nach ein paar kleinen Änderungen nun ein anderes Fehlerbild, ich bekomme keine Exceptions mehr und mein Kernel hält auch nicht mehr an.

Aber sobald ich mehr als einen Task initialisiere passiert nichtsmehr außer die Bestätigung eines einzigen Timerinterrupts (dabei ist es egal ob das TSS in Ring0 oder Ring3 ist).

Ein Task läuft einwandfrei. Und wenn ich 2 eintrage und in dem Interrupthandler bei dem Timerinterrupt die schedule und set_tss_entry Funktion auskommentiere:

if (cpu->intr == 0x20) {
 kputs("Timerinterrupt vor");
 //new_cpu = schedule(cpu);
 //set_tss_entry(1, (unsigned long) (new_cpu + 1));
 kputs("Timerinterrupt nach");
}

bekomme ich zwar die Bestätigung von konstant aufeinanderfolgenden Timerinterrupts aber meine Tasks machen gar nichts… eigtl sollte ja zumindest A auf dem Bildschirm vom ersten Task ausgegeben werden auch wenn kein Taskswitch stattfindet...

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #63 am: 25. November 2014, 21:04 »
Also gut hab mich mal ein bisschen im Debugging geübt und die Werte ausgelesen, die init_task zurückgibt... also den CPU Status.

Dabei bin ich auf folgendes gestoßen... die Werte die der erste Aufruf von init_task zurückgibt sind ja noch ganz ok, und wie erwartet: (alles hexadezimale Zahlen):

eax: 0
ebx: 0
ecx: 0
edx: 0
esi: 0
edi: 0
ebp: 0
eip: 100d29 (Einsprungpunkt des Tasks)
cs: 1b
eflags: 200
esp: 21000
ss: 23

Aber bei den Rückgabewerten des 2. init_task aufrufs:

eax: eef3ff
ebx: eef3f0
ecx: e2c3f0
edx: eef3f0
esi: eef3f0
edi: ff54f0
ebp: 313df0
eip: e987f0 (Adresse existiert in meinem Kernel nicht...)
cs: eef3f0
eflags: eef3f0
esp: eef3f0
ss: eef3f0

Ich versuch jetz grad mal rauszufinden was es mit dem "eef3f0" auf sich hat...

« Letzte Änderung: 25. November 2014, 22:14 von s137 »

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #64 am: 25. November 2014, 22:13 »
edit: Ergänzung:

Hab mal in meiner handle_interrupt Funktion beim ersten Timerinterrupt auch debuggt:

Das hier is rausgekommen, theoretisch müssten das die Werte sein die vor dem Aufruf des ersten Timerinterrupts von der CPU gesichert worden sind:

eax: 0
ebx: 10000
ecx: b8000
edx: b8f29
esi: 0
edi: 0
ebp: 126204
eip: 100d3f (Ende der init Funktion: Endlosschleife mit << asm volatile("hlt;"); >>)
cs: 8
eflags: 200246
esp: ffffffff
ss: 0

vielleicht kann man ja da noch was rauslesen...

OsDevNewbie

  • Beiträge: 282
    • Profil anzeigen
    • YourOS Kernel
Gespeichert
« Antwort #65 am: 25. November 2014, 22:56 »
Verwendest du hardware Multitasking odersoftware Multitasking?
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 #66 am: 26. November 2014, 06:27 »
Also ich habe dieses Tutorial für mein Multitasking benutzt: http://www.lowlevel.eu/wiki/Teil_6_-_Multitasking denke mal es ist Hardware Multitasking... Ich weiß es aber nicht genau...

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #67 am: 26. November 2014, 09:31 »
Nein, das ist Software-Multitasking. Das mag vielleicht auf den ersten Blick komisch klingen, aber das ist schneller und besser als Hardware-Multitasking (außer manchmal, wenn Software-Multitasking gar nicht geht, aber das würde hier zu weit führen).

Was dein Problem betrifft, sehen ja alle Werte kaputt aus. Ich würde an deiner Stelle mal bei der Initialisierung der Tasks und bei jedem Taskwechsel den Stackpointer (oder cpu_state, der ja auf dem Stack liegt und damit ungefähr dasselbe sein müsste) von altem und neuem Task ausgeben. Da müsstest du dann zumindest mal sehen, ob dein cpu_state-Pointer verrutscht ist und auf was falsches zeigt oder ob du den Inhalt der Struktur aus Versehen überschrieben hast.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #68 am: 26. November 2014, 15:45 »
Also hier mal die Ergebnisse des Debuggens: (Instrucion Pointer (eip), Codesegment (cs), Stackpointer (esp)):

Rückgabe von Task 1 Initialisierung:

eip: 100d95 (Einsprungpunkt des ersten Tasks)
cs: 1b (Codesegment Userspace)
esp: 21000


Rückgabe von Task 2 Initialisierung:

eip: e987f0 (Adresse existiert nicht)
cs: eef3f0
esp: eef3f0

erster Timerinterrupt cpu_state vor Taskswitch:

eip: 100d93 (Ende der init Funktion: Endlosschleife mit << asm volatile("hlt;"); >>)
cs: 8
esp: ffffffff

erster Timerinterrupt new cpu_state nach Taskswitch:

eip: e987f0 (Adresse existiert nicht)
cs: eef3f0
esp: eef3f0
« Letzte Änderung: 26. November 2014, 17:44 von s137 »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #69 am: 26. November 2014, 16:06 »
Rückgabe von Task 1 Initialisierung:
Rückgabe von Task 1 Initialisierung:
Ich weiß ja nicht, wie oft du Task 1 initialisierst, aber unabhängig davon, was du mit dem zweiten Block wirklich meintest, sieht das schon kaputt aus (was dir hoffentlich auch aufgefallen ist).
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #70 am: 26. November 2014, 17:33 »
Sry, hab mich verschrieben.. Meinte beim 2. Mal natürlichen Task 2.. Mir is schon aufgefallen, dass beim 2.Task und nach dem Taskswitch kaputte werte rauskommen.. Aber ich weiß halt nicht woher die kommen..

Jetzt allerdings noch eine Verständnisfrage zu oben... Wann springt mein Kernel denn in den Task den ich initialisiere? Normalerweise doch erst wenn der erste Timerinterrupt kommt und meine schedule Funktion aufgerufen wird... Das wirft für mich noch eine Frage auf... Wann kommt der erste Timerinterrupt und von was hängt das ab?
« Letzte Änderung: 26. November 2014, 17:49 von s137 »

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #71 am: 26. November 2014, 19:19 »
Der erste Timerinterrupt wird ausgelöst, nachdem du Interrupts aktiviert hast (mit STI), allerdings nicht unbedingt sofort, sondern erst nach einer (für dich) zufälligen Zeitspanne.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #72 am: 26. November 2014, 19:29 »
Das heißt irgendwann, kurz nachdem ich die Interrupts aktiviert habe, kommt der erste Timerinterrupt, meine schedule Funktion wird aufgerufen und mein Kernel springt in den Task den ich vorher initialisiert habe. Und dann beim zweiten Timerinterrupt, wird meine schedule Funktion erneut aufgerufen und in den nächsten Task gesprungen. Sehe ich das so richtig? '

Dann hätte ich noch eine Frage, wozu brauche ich den Eintrag ins TSS und wieso trage ich dort "new_cpu + 1" als ersten Eintrag immer wieder neu ein?

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #73 am: 26. November 2014, 19:36 »
Das ist außerdem noch meine init_task() könnte ja sein dass man da nen Fehler entdeckt... der Rückgabewert beim ersten Aufruf ist ganz normal, aber beim 2. Mal chaotisch siehe oben.

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 = 0x200, // 200 ?!
    };


    /*
     * 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();
    //struct task* task;
    task->cpu_state = state;
    task->next = first_task;
    first_task = task;
    return task;
}


Ich würde halt irgendwie mal drauf tippen dass bei dem "struct task* task = pmm_alloc()" also beim allozieren von Speicher für die Taskstruktur was schiefgeht.. aber dann dürfte es ja beim ersten mal auch schon nicht funktionieren oder?
« Letzte Änderung: 26. November 2014, 19:41 von s137 »

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #74 am: 26. November 2014, 21:57 »
Wie sieht denn der Code aus, der init_task() aufruft und die (falschen) Debugmeldungen ausgibt?
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #75 am: 26. November 2014, 22:08 »
In der init.c:

      struct task* task = init_task(test_task_1);

      struct cpu_state* cpu = task->cpu_state;

      debug(cpu, 0, "Task 1:");

Hier noch den Deklaration der Funktion Test Task:


void test_task_1(void);

Und an anderer Stelle die Funktion selbst:

void test_task_1(void)
{
 while(1) {
 kputs("A");
 }
}

Bei Task 2 ist es dasselbe nur mit "B".

Hier noch der Code von debug.c die über eine Headerdatei in der init.c eingebunden ist:

#include "console.h"
#include "debug.h"
#include "task.h"

void debug(struct cpu_state* cpu, int verbose_level, char text[]) {

           kputs(text);
           kputs("\n");

  if(verbose_level == 0) {

           kputs("\n Register eip: ");
           kputn(cpu->eip, 16);
           kputs("\n Register cs: ");
           kputn(cpu->cs, 16);
           kputs("\n Register esp: ");
           kputn(cpu->esp, 16);

  }

  if(verbose_level == 1) {

           kputs("\n Register eax: ");
           kputn(cpu->eax, 16);
           kputs("\n Register ebx: ");
           kputn(cpu->ebx, 16);
           kputs("\n Register ecx: ");
           kputn(cpu->ecx, 16);
           kputs("\n Register edx: ");
           kputn(cpu->edx, 16);
           kputs("\n Register esi: ");
           kputn(cpu->esi, 16);
           kputs("\n Register edi: ");
           kputn(cpu->edi, 16);
           kputs("\n Register ebp: ");
           kputn(cpu->ebp, 16);
           kputs("\n Register eip: ");
           kputn(cpu->eip, 16);
           kputs("\n Register cs: ");
           kputn(cpu->cs, 16);
           kputs("\n Register eflags: ");
           kputn(cpu->eflags, 16);
           kputs("\n Register esp: ");
           kputn(cpu->esp, 16);
           kputs("\n Register ss: ");
           kputn(cpu->ss, 16);
  }

}

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #76 am: 26. November 2014, 23:03 »
Das heißt irgendwann, kurz nachdem ich die Interrupts aktiviert habe, kommt der erste Timerinterrupt, meine schedule Funktion wird aufgerufen und mein Kernel springt in den Task den ich vorher initialisiert habe. Und dann beim zweiten Timerinterrupt, wird meine schedule Funktion erneut aufgerufen und in den nächsten Task gesprungen. Sehe ich das so richtig?
Ja.

Dann hätte ich noch eine Frage, wozu brauche ich den Eintrag ins TSS und wieso trage ich dort "new_cpu + 1" als ersten Eintrag immer wieder neu ein?
Du machst Software-Multitasking. Das heißt, du hast genau ein einziges TSS, welches du beim Taskwechsel immer wieder neu befüllst und dann der CPU wieder vor die Nase wirfst. (Bei Hardware-Multitasking hättest du stattdessen ein TSS pro Task, und würdest die CPU immer wieder ein anderes aktivieren lassen, wenn du wechseln möchtest.)

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #77 am: 27. November 2014, 07:40 »
Oh ok naja dann geht ja anscheinend schon bei der 2. Taskinitialisierung was schief.. Aber warum erst bei der 2.
Wenns an der Speicherallokation für die Taskstruktur läge, müsste es doch beim 1. Mal auch schon nicht funktionieren oder?

Aber wieso dann "new_cpu +1" was macht dieses Plus eins für das TSS..?

kevin

  • Administrator
  • Beiträge: 2 767
    • Profil anzeigen
Gespeichert
« Antwort #78 am: 27. November 2014, 09:59 »
Wenn deine Initialisierung für Task 2 genauso aussieht wie die für Task 1, dann geht der Inhalt ja ziemlich sofort kaputt nachdem du ihn eingetragen hast. Mit gdb und Singlestep müsstest du die Stelle dann schnell finden können. Du könntest dir allerdings auch noch die Rückgabewerte von pmm_alloc() ausgeben lassen, nicht dass dort etwas schiefgeht und du in einem ROM landest oder ähnliche Späße.
Thou shalt not follow the NULL pointer, for chaos and madness await thee at its end.

s137

  • Beiträge: 110
    • Profil anzeigen
Gespeichert
« Antwort #79 am: 27. November 2014, 16:23 »
Was genau muss ich denn mit gdb machen? Denn wenn ich den Kernel mit gdb debugge dann sagst er mir erstmal dass meine multiboot_structure = 0x0 ist.. was ja auch logisch ist, wenns nicht auf echter hardware oder einem emulator ausgeführt wird.

 

Einloggen