Autor Thema: Multitasking, die 1000ste ..  (Gelesen 11567 mal)

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« 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
 

Svenska

  • Beiträge: 1 792
    • Profil anzeigen
Gespeichert
« Antwort #1 am: 28. September 2011, 09:56 »
Die handle_interrupt()-Funktion wird vom Interrupt-Handler-Stub (in der Assembler-Datei) aufgerufen.
Den CPU-Zustand kriegt sie auch von da und gibt ihn dorthin zurück.

Was meinst du mit Punkten? Die Sterne? Die geben an, dass es sich um Zeiger handelt.

Also: handle_interrupt() ruft deinen Scheduler auf, der übernimmt den alten CPU-Zustand (speichert den aktuellen Zustand für den noch aktuellen Task), wechselt den Task und gibt den neuen CPU-Zustand (also den gespeicherten Zustand des neuen Tasks) zurück. Das handle_interrupt() ändert den CPU-Zustand dann auf den des neuen Tasks.

Alle deine Tasks müssen also eine "struct cpu_state" speichern.

Gruß,
Svenska

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #2 am: 28. September 2011, 13:07 »
Hallo El-Tomato,

hast du auch den Teil 5 gelesen? Der Assembler-Teil gehört in intr_common_handler, und die kannst du nicht einfach so in eine C-Funkiton(auch nicht per inline-asm) stecken, weil sie mit einem 'iret' und nicht 'ret' endet, und du außerdem genau wissen must wie der stack aussieht, wo du dir innerhalb einer c-funktion nicht 100%ig sicher sein kanst.

Der Interupthandler wird in dem von dir gezeigten asm-teil aufgerufen. Der parameter (esp) wird auf den stack gepusht, und der rückgabe wert landet in eax, das ist Konvention. Du sicherst allso den CPU zustand auf dem stack, lässt dir von handle_interrupt() nen neuen stack pointer zurückgeben und stellst den cpu zustand von dem neuen stack wieder her.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #3 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

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #4 am: 05. October 2011, 15:52 »
Ja, das hast du richtig verstanden.
Wobei du nicht nur die paar Segmentrigister, sondern alle Register mit denen des neuen Tasks laden musst. Und da die sich alle auf dem Stack befinden reicht es statt pop eax, einfach ESP mit dem Wert zu laden den der Task letztes mal an _irq_handler übergeben hat.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #5 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
« Letzte Änderung: 05. October 2011, 17:39 von El-Tomato »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #6 am: 05. October 2011, 18:12 »
pop eax ;parameter vom stack nehmen

Der Parameter liegt nicht oben auf dem Stack. Deswegen kommst du da nicht mit einem einfachen pop ran. Stattdessen kannst du den Wert so auslesen:
mov eax, [esp + 4]
Edit in eigener Sache: *yay* vierstellig
« Letzte Änderung: 05. October 2011, 18:16 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #7 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

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #8 am: 05. October 2011, 18:30 »
Was meinst du damit? Exception 5 wird von deinem OS gefangen?
Dieser Text wird unter jedem Beitrag angezeigt.

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #9 am: 05. October 2011, 18:33 »
genau das passiert ..
Ich steh gerade total auf dem Schlauch :/

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #10 am: 05. October 2011, 18:39 »
Eine Möglichkeit wären falsch eingestellte IRQs, das heißt PIC falsch konfiguriert. Das glaube ich allerdings nicht.

Wahrscheinlicher ist, dass die CPU an eine falsche Adresse springt. Wie genau verwaltest du die Stacks? Insbesondere: Wie erstellst du den Stack zu dem du springst? switch_task(curESP) ist auf jeden Fall nicht korrekt, weil curESP ja auf nichts zeigt, das von einem popa gefolgt von einem ret verarbeitet werden kann.
« Letzte Änderung: 05. October 2011, 18:42 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #11 am: 05. October 2011, 18:40 »
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?

nein, das kann so nicht gehen.
nach dem du esp gespeichert hast, wird mindestens noch der parameter, eip und die allzweicregister(pusha) auf den stack gepuscht (esp also verändert),
wenn du jetzt esp mit dem gespeicherten wert lädst, hast du all das auf dem neuen stack noch gar nicht drauf, und popa lädt irgend einen müll. Viel schlimmer ist aber
das ret auch irgend einen müll vom stack nach eip lädt. also einen 'jmp RANDOM' ausführt.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #12 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?!
« Letzte Änderung: 05. October 2011, 19:05 von El-Tomato »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #13 am: 05. October 2011, 19:09 »
Im Tutorial wird der Task Switch hier (Zeile 67) ausgelöst.

Solang du innerhalb von C bist kannst du nicht einfach mal den stack aus tauschen, weil du dich nicht auf einen bestimmten zustand verlassen kannst.
Deshalb macht man das im assembler stub des Interupthandlers.


„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #14 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?
« Letzte Änderung: 05. October 2011, 22:27 von El-Tomato »

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #15 am: 05. October 2011, 22:33 »
Du rufst in irq_common_stub zweimal irq_handler handler auf. Einmal sollte genügen.

Außerdem wechselst du nicht den Stack im irq_handler (wegen des pop eax).

Wenn das nicht das Problem behebt, solltest du genauer analysieren, wo genau die Exception auftritt. Du kannst zum Beispiel den Emulator befragen (qemu z.B. mit den Parameter -d int aufrufen und dann in der Datei qemu.log bzw. /tmp/qemu.log nachschauen), oder deiner eigenen Ausgabe vertrauen (das eip: 1063348). Interessant ist vor allem welcher Befehl ausgeführt wird.
« Letzte Änderung: 05. October 2011, 22:34 von Jidder »
Dieser Text wird unter jedem Beitrag angezeigt.

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #16 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 :/

Jidder

  • Administrator
  • Beiträge: 1 625
    • Profil anzeigen
Gespeichert
« Antwort #17 am: 05. October 2011, 22:43 »
Wenn das so ist, würde ich sagen, dass der Fehler wahrscheinlich nicht in dem Code liegt, den du eben gepostet hast.
Die Ausgabe "cs: 0" sieht allerdings verdächtig aus. Du solltest überprüfen, was du auf den Stack legst bzw. was du mit dem Stack machst. Oder die Ausgabefunktion.
Dieser Text wird unter jedem Beitrag angezeigt.

El-Tomato

  • Beiträge: 12
    • Profil anzeigen
Gespeichert
« Antwort #18 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 :(
« Letzte Änderung: 06. October 2011, 05:17 von El-Tomato »

MNemo

  • Beiträge: 547
    • Profil anzeigen
Gespeichert
« Antwort #19 am: 06. October 2011, 10:25 »
Es ist keine gute Idee die Segmentregister mit 0 zu Initialisieren. Möglicherweise löst das schon direkt ein #GP aus, aber spätestens der zugriff über ein eines der genullten Register tut das. Also quasi jeder zugriff auf (Globalen-)Speicher.
„Wichtig ist nicht, besser zu sein als alle anderen. Wichtig ist, besser zu sein als du gestern warst!“

 

Einloggen