#define KERNEL_STACK_SIZE 4096
typedef struct {
unsigned long *stack_base;
unsigned long *stack_ptr;
} Task;
Task *createTask(void *entry) {
// speicher für den stack anfordern
char *stack = malloc(KERNEL_STACK_SIZE);
if(stack == NULL)
return NULL;
// stack-pointer berechnen (stack wächst von oben nach unten)
unsigned long *sp = (unsgined long *)(stack + KERNEL_STACK_SIZE);
// alle register auf den stack pushen, die dein taskswitch code erfordert
// ss (wird vom iret gepopt)
*(sp--) = 0x10;
// esp (wird vom iret gepopt)
// in diesem beispiel muss der task selbst seinen esp auf einen gültigen wert setzen
*(sp--) = 0;
// eflags (wird vom iret gepopt)
// ich weiß nicht aus dem kopf, was für eflags richtig sind
*(sp--) = 0;
// cs (wird vom iret gepopt)
*(sp--) = 0x8;
// eip (wird vom iret gepopt)
*(sp--) = (unsigned long)entry;
// eax, ebx, ecx, edx, ebp, esi, edi
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
*(sp--) = 0;
// ds, es, fs, gs
*(stack--) = 0x10;
*(stack--) = 0x10;
*(stack--) = 0x10;
*(stack--) = 0x10;
Task *task = malloc(sizeof (Task));
if(task == NULL)
return NULL;
task.stack_base = stack;
task.stack_ptr = sp;
return task;
}
task.stack_base muss immer im TSS als Ring0 ESP eingetragen werden, wenn man den Task wechselt. Um den Task zu wechseln im Timer Interrupt, müssen alle register gepushed werden, der ESP in task.stack_ptr gesichert werden, der neue task muss ausgewählt werden, new_task.stack_base ins TSS eingetragen werden, new_task.stack_ptr muss in ESP eingetragen werden, alle register müssen gepopt werden, und dann muss iret ausgeführt werden.