Beiträge anzeigen

Diese Sektion erlaubt es dir alle Beiträge dieses Mitglieds zu sehen. Beachte, dass du nur solche Beiträge sehen kannst, zu denen du auch Zugriffsrechte hast.


Nachrichten - El-Tomato

Seiten: [1]
1
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 06. October 2011, 17:07 »
Ick könnt dir knutschen, et funktioniert :D

Ich danke dir und Jidder schonmal recht herzlich :)


Für alle die es Interessiert oder die selben Probleme haben sollten, hier mein letzter Stand:

Der ASM IRQ-Stub:
irq_common_stub:

    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    push esp
    call _irq_handler

    mov esp, eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8

    iret

Das dazugehörige Struct im init_task() :
struct regs new_state = {
        .eax = 0,
        .ebx = 0,
        .ecx = 0,
        .edx = 0,
        .esi = 0,
        .edi = 0,
        .ebp = 0,
        //.esp = unbenutzt (kein Ring-Wechsel)
        .eip = (uint32_t) entry,
 
        /* Ring-0-Segmentregister */
        .cs  = 0x08,
        //.ss  = unbenutzt (kein Ring-Wechsel)
 
        /* IRQs einschalten (IF = 1) */
        .eflags = 0x202,

.gs=16,
.fs=16,
.es=16,
.ds=16,

.esp=0,
.useresp=0,
.ss=0,
.int_no=0,
.err_code=0,

    };

Danke, nochmals ;)
2
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 06. October 2011, 16:49 »
ein pop fehlt aber trotzdem, oder? ich pushe ja vor dem call ESP auf den Stack..

Aber was meinst du mit "ds, es, fs und gs mit 16 initialisieren"? Einfach hart kodieren?
Weil im Code im Wiki werden diese Register auch mit 0 initialisiert .. die werden im wiki überhaupt nicht initialisiert ..

Hatte gerade die Idee, dass der zu große fs Wert auch durch die fehlende Initialisierung entstehen könnte ..
Habe jetzt jede Variable des structs mit 0 initialisiert, trotzdem bekomme ich einen GPF :/
3
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 06. October 2011, 16:36 »
Ich bin da nach dem Wiki Eintrag vorgegangen ..

Mittlerweile bin ich etwas weiter ..
Mein ASM Code ist einfach falsch.

Der sieht aktuell so aus:
irq_common_stub:

    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    push esp

    call _irq_handler

    pop ebx                ; Hier bin ich mir nicht
    mov esp, ebx         ; sicher, ob das richtig ist

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8

    iret

Jemand sagte mir, ich solle solle mich um den ESP kümmern und den auf den Wert einstellen, den er vor beladen
des Stacks (für die Parameter der C-Funktion) hatte ..
Aber wenn ich am Anfang den ESP auf den Stack pushe und direkt vor dem iret wieder ins esp poppe, tut sich einfach
überhaupt garnichts :/
4
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 22:52 »
Also ich habe jetzt Code aus dem Tutorial Teil 6 nochmal komplett rüber kopiert und nur "cpu_state" durch "regs" getauscht ..
Jetzt steht im CS der Wert 8.

Trotzdem bekomme ich einen General Protection Fault :/

Ich total ratlos  :? :?

Edit:
Ich hab jetzt die Funktion, welche den Fehler verursacht .. Nur warum weiß ich nicht  :|
Benutze ich putch(), verabschiedet sich das Teil .. Der Compiler gibt aber weder Fehler noch Warnung in dieser Datei aus ..

Nehme ich die putch() aus dem Task raus, steht alles (Auch keine Interrupts kommen durch ..)

Irgendwer ne Ahnung?

Edit2:
Jippie! Das Multitasking funktioniert jetzt ..
allerdings kann ich überhaupt keine C-Funktionen nutzen ..
Habe es mit dem Systemlautsprecher ausprobiert, der verschiedene Töne von sich gibt. (Mittels inline asm outb)
Aber wie komme ich nun an meine ganzen C-Funktionen?

Edit3:
In QEmu funktionierts wunderbar ..
Aber VMWare 8 zeigt mir nen General Protection Fault :/

Edit4:
Ich hab mal die Register, vor und nach dem switch, ausgeben lassen (Direkt danach crasht er mit nem GPF)


Ich bin, was das angeht, noch blutiger Anfänger, aber mir ist aufgefallen, dass der wert in fs sehr hoch ist.
Ist FS kein 16 Bit Register? Warum holt sich VMWare dann einen so großen Wert? Das könnte doch schon der Fehler sein, oder?

Fällt noch wem was auf?

btw .. auf nem echten PC funktioniert es auch nicht :(
5
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 22:37 »
Sry, hatte einige Zeilen auskommentiert und wollte die im Code Tag löschen ..
Da lief was falsch .. Mein Code sieht eigentlich so aus:

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push esp
    call _irq_handler

    mov esp, eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

Sry, mein Fehler :/
6
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 22:25 »
Ich glaube ich komme der Sache näher ..

Den Code habe ich schon gefunden ..

Mein Problem ist einfach nur, dass ich den interrupt handler etwas anders integriert habe .. (Dump davon gibts weiter unten ..)

statt cpu_state benutze ich folgendes Struct:
struct regs
{
    unsigned int gs, fs, es, ds;
    unsigned int edi, esi, ebp, esp, ebx, edx, ecx, eax;
    unsigned int int_no, err_code;
    unsigned int eip, cs, eflags, useresp, ss;   
};

Mein IRQ Handler sieht wie folgt aus:
struct regs* irq_handler(struct regs *r)
{
    struct regs* new_cpu = r;
    void (*handler)(struct regs *r);

    handler = irq_routines[r->int_no - 32];
    if (handler)
    {
        handler(r);
    }
   
    if (r->int_no >= 40)
    {
        outportb(0xA0, 0x20);
    }
   
    if (r->int_no == 0x20) {
        new_cpu = schedule(r);
    }

    outportb(0x20, 0x20);

    return new_cpu;

}

Und das hier ist der irq stub, der den irq_handler aufruft
irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    push esp
    mov eax, _irq_handler
    call eax
    call _irq_handler

    pop eax

    mov esp, eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

Jetzt zum Problem:
sobald der Interrupt kommt, und schedule() aufgerufen wird, scheint er alles richtig in die Register zu laden (siehe dump unten),
aber danach verabschiedet sich das Ding mit einem Fehler 0, General Protection Fault.

Der Dump sieht wie folgt aus:
CPU HALT
gs: 0, fs: 0, es: 0, ds: 0
edi: 0, esi: 0, esp: 1065599
eax: 0, ebx: 1085824, ecx: 0, edx: 1065599
int_no: 13, err_code: 0
eip: 1063348, cs: 0, ss: 1065599
eflags: 66054, useresp: 1050769

Hat wer ne Idee?
7
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 18:53 »
Am IRQ kann es nicht liegen, da ich den Switch im Moment noch per Hand starte ..

OK, den quatsch mit dem curESP hab ich jetzt verworfen.

Ich habe mich meist an den Einsteiger-Guide Teil 6 gehalten ( http://www.lowlevel.eu/wiki/Teil_6_-_Multitasking ) gehalten und auch zwei Tasks (task_a() und task_b()) initialisiert.

Das Problem wird wahrscheinlich sein, dass der esp im task_state[0] = 0 ist :D (Da bin ich mir sogar sicher! :P)
Aber wie kriege ich den Task zum Laufen?

Mein aktueller Code sieht aus wie folgt:
(die blabla() ist im Moment die Funktion, mit der ich den Task Switch anstoßen will .. )

UPDATE: Nochmal mit Syntax Highlighting: http://pastebin.com/5aQJzeUn

#include <system.h>
#include <stdio.h>

//Prototypen
int mt_task_switch();

static uint8_t stack_a[4096];
static uint8_t stack_b[4096];

static int current_task = -1;
static int num_tasks = 2;
static struct cpu_state* task_states[2];

void task_a(void)
{
    while (1) {
        printf("A");
    }
}
 
void task_b(void)
{
    while (1) {
        printf("B");
    }
}

struct cpu_state* init_task(uint8_t* stack, void* entry)
{
    /*
     * 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 = unbenutzt (kein Ring-Wechsel)
        .eip = (uint32_t) entry,
 
        /* Ring-0-Segmentregister */
        .cs  = 0x08,
        //.ss  = unbenutzt (kein Ring-Wechsel)
 
        /* 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;
 
    return state;

}

void init_multitasking(void)
{
    task_states[0] = init_task(stack_a, task_a);
    task_states[1] = init_task(stack_b, task_b);
}
 
/*
 * Gibt den Prozessorzustand des naechsten Tasks zurueck. Der aktuelle
 * Prozessorzustand wird als Parameter uebergeben und gespeichert, damit er
 * beim naechsten Aufruf des Tasks wiederhergestellt werden kann
 */
struct cpu_state* schedule(struct cpu_state* cpu)
{
    /*
     * Wenn schon ein Task laeuft, Zustand sichern. Wenn nicht, springen wir
     * gerade zum ersten Mal in einen Task. Diesen Prozessorzustand brauchen
     * wir spaeter nicht wieder.
     */
    if (current_task >= 0) {
        task_states[current_task] = cpu;
    }
 
    /*
     * Naechsten Task auswaehlen. Wenn alle durch sind, geht es von vorne los
     */
    current_task++;
    current_task %= num_tasks;
 
    /* Prozessorzustand des neuen Tasks aktivieren */
    cpu = task_states[current_task];
 
    return cpu;
}

struct cpu_state* handle_interrupt(struct cpu_state* cpu)
{
printf("handle_interrupt called, finally :P\n");
struct cpu_state* new_cpu = cpu;

    if (cpu->intr == 0x20) {
        new_cpu = schedule(cpu);
    }

 
    return new_cpu;
}






int mt_install()
{
init_multitasking();
timer_add_handler((fp)&mt_task_switch);
}

int mt_task_switch()
{

return 0;
}

void blabla()
{

printf("Task_A esp = %i\n", task_states[0]->esp);
printf("Task_B esp = %i\n", task_states[1]->esp);

//switch_task(task_states[0]->esp);

}

Meine Frage ist jetzt, woher bekomme ich den ESP des Tasks, wenn der quasi noch uninitialisiert ist?!
8
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 18:33 »
genau das passiert ..
Ich steh gerade total auf dem Schlauch :/
9
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 18:27 »
Jetzt krieg ich nen Out of Bounds Panic  :-o

global _switch_task
_switch_task:
mov eax, [esp + 4] ;parameter vom stack nehmen
pusha
xchg esp, eax
popa

ret

Ich verlier grad die Lust :D
10
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 17:15 »
Gut, also sollte das so funktionieren:

Wenn der PIC die C-Funktion aufruft, hole ich mir aus dem Struct des nächsten Tasks, die ESP und switche dann die Register. Richtig?

Das ASM Unterprogramm würde dann so aussehen:


global _switch_task
_switch_task:
pop eax ;parameter vom stack nehmen
pusha
xchg esp, eax
popa

ret


und Aufruf über C-Funktion "switch_task(uint32_t neuer_esp)", oder?


Das tuts nur leider nicht :( Sobald ich switch_task aufrufe, bleibt alles stehen ...

Wenn ich mir mit
uint32_t curESP;
asm ( "mov %%esp, %0;" : "=r"(curESP));
den ESP hole und switch_task(curESP); aufrufe, sollte er ja eigentlich normal weiter funktionieren ..
Selbst das tut er nicht. Das ganze System steht einfach still :/ Woran könnte das liegen?

MfG
11
Lowlevel-Coding / Re: Multitasking, die 1000ste ..
« am: 05. October 2011, 15:16 »
Hallo, danke für die Antworten :)

Habe ich das richtig verstanden?
Wenn der PIC feuert, und die IRQ Routine ausführt, werden die Register auf den Stack gepusht, der IRQ Handler ausgeführt und anstatt danach den alten Zustand zu popen, schiebe ich die Werte des nächsten Tasks in die CPU?

Mein aktueller IRQ Handler sieht wie folgt aus:
extern _irq_handler

irq_common_stub:
    pusha
    push ds
    push es
    push fs
    push gs

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov eax, esp

    push eax
    mov eax, _irq_handler
    call eax
    pop eax

    pop gs
    pop fs
    pop es
    pop ds
    popa
    add esp, 8
    iret

(Ich habe mich dabei an das Tutorial von Brandon F. gehalten)

Sehe ich das richtig?
Nachdem _irq_handler aufgerufen wurde, und eax gepopt wurde, müsste ich, statt des vorherigen Zustands, den des nächsten Tasks in die Register, gs, fs, es und ds schieben?

MfG
12
Lowlevel-Coding / Multitasking, die 1000ste ..
« am: 28. September 2011, 04:13 »

Moin,

da ich im Moment in der Uni das Fach "Betriebssysteme" habe, bin ich gerade dabei ein eigenes OS zusammen zu puzzeln, um die Abläufe da etwas besser zu verstehen. :P

Nun bin ich soweit, dass ich nen kleinen PMode Kernel habe und dabei Multitasking zu implementieren.
Dabei bin ich auf das Tutorial auf den Wiki Seiten gestoßen.

Zuerst mal größtes Lob und besten Dank, dass ihr OS-Dev Neulingen, wie mir, nen Anlaufpunkt bietet.  :-)


Los geht's..
Ich habe (zum rum-experimentieren) eine .c Datei mit einer Einstiegsfunktion "mt_install()" und eine "mt_task_switch()", die vom PIC aufgerufen wird.

Nun bin ich nach eurem Tutorial (http://www.lowlevel.eu/wiki/Teil_6_-_Multitasking) vorgegangen und habe die entsprechenden Funktionen implementiert.

Jetzt hänge ich aber bei
struct cpu_state* handle_interrupt(struct cpu_state* cpu)
Ich verstehe einfach nicht woher sie den cpu-parameter bekommt und wohin er den cpu_state returnt. Und was die Punkte darstellen sollen, versteh ich auch nicht :D

Angenommen, ich möchte einen simplen context-switch in die "task_a()"-Funktion machen .. Wie krieg ich das gebacken?

Wenn die vom PIC, zyklisch aufgerufene Funktion "mt_task_switch()" die "handle_interrupt(struct cpu_state* cpu)" aufrufen sollte, kann ich dann als Parameter eine
globale Variable übergeben und den Rückgabewert wieder in dieser Speichern?

zu guter letzt steht im Tutorial folgendes:
...
    // Handler aufrufen
    // Der Rueckgabewert ist der Prozessorzustand des moeglicherweise
    // gewechselten Tasks. Wir muessen also den Stack dorthin wechseln
    // um die Register wiederherzustellen.
    push %esp
    call handle_interrupt
    mov %eax, %esp
 
    // CPU-Zustand wiederherstellen
    ...

Wie kann ich das in C-Code verwursten? Ich habs schon mit inline ASM versucht, bekomme schon bei "push %esp" einen kernel panic.
Generell weiß ich auch noch nicht so wirklich was der gegebene Code macht.  :?

Aktuell sieht mein Code folgendermaßen aus:
#include <system.h>
#include <stdio.h>

struct cpu_state {
    // Von Hand gesicherte Register
    uint32_t   eax;
    uint32_t   ebx;
    uint32_t   ecx;
    uint32_t   edx;
    uint32_t   esi;
    uint32_t   edi;
    uint32_t   ebp;
 
    uint32_t   intr;
    uint32_t   error;
 
    // Von der CPU gesichert
    uint32_t   eip;
    uint32_t   cs;
    uint32_t   eflags;
    uint32_t   esp;
    uint32_t   ss;
};

struct cpu_state* current_cpu = 0;

static uint8_t stack_a[4096];
static uint8_t stack_b[4096];

static int current_task = -1;
static int num_tasks = 2;
static struct cpu_state* task_states[2];

void task_a(void)
{
    while (1) {
        printf("A");
    }
}
 
void task_b(void)
{
    while (1) {
        printf("B");
    }
}

struct cpu_state* init_task(uint8_t* stack, void* entry)
{
    /*
     * 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 = unbenutzt (kein Ring-Wechsel)
        .eip = (uint32_t) entry,
 
        /* Ring-0-Segmentregister */
        .cs  = 0x08,
        //.ss  = unbenutzt (kein Ring-Wechsel)
 
        /* 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;
 
    return state;

}

void init_multitasking(void)
{
    task_states[0] = init_task(stack_a, task_a);
    task_states[1] = init_task(stack_b, task_b);
}

/*
 * Gibt den Prozessorzustand des naechsten Tasks zurueck. Der aktuelle
 * Prozessorzustand wird als Parameter uebergeben und gespeichert, damit er
 * beim naechsten Aufruf des Tasks wiederhergestellt werden kann
 */
struct cpu_state* schedule(struct cpu_state* cpu)
{
    /*
     * Wenn schon ein Task laeuft, Zustand sichern. Wenn nicht, springen wir
     * gerade zum ersten Mal in einen Task. Diesen Prozessorzustand brauchen
     * wir spaeter nicht wieder.
     */
    if (current_task >= 0) {
        task_states[current_task] = cpu;
    }
 
    /*
     * Naechsten Task auswaehlen. Wenn alle durch sind, geht es von vorne los
     */
    current_task++;
    current_task %= num_tasks;
 
    /* Prozessorzustand des neuen Tasks aktivieren */
    cpu = task_states[current_task];
 
    return cpu;
}

//wird am Anfang aufgerufen, Observer-Pattern ..
int mt_install()
{
timer_add_handler((fp)&mt_task_switch);
init_multitasking();
return 0;
}

//wird zyklisch vom PIC aufgerufen
int mt_task_switch()
{
//hier fehlt mir die Idee .. Wir überrede ich meine Möhre zum Task-Switch?
return 0;
}


Kann mir wer nen Wink in die richtige Richtung geben?

Danke schonmal ;)

MfG
 
Seiten: [1]

Einloggen