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.
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
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