#include #include int lastPid; int current_pid; struct task* first_task = NULL; struct task* current_task = NULL; int num_tasks; static void leerlauf_task() { while(1) { asm("int $0x31"::"a"(0x1)); // nächster Task } } void get_rs232_input() { while(1) { char c; asm("int $0x30":"=a"(c):"a"(12)); if(c != 0) keyboard_buffer = c; kprintf("%c", c); } } struct task *getNextTask(struct task *task) { if (task == NULL) { task = first_task; } else { task = task->next; if (task == NULL) { task = first_task; } } if(!task->running) { task = task->next; if (task == NULL) { task = first_task; } } return task; } /* * Jeder Task braucht seinen eigenen Stack, auf dem er beliebig arbeiten kann, * ohne dass ihm andere Tasks Dinge ueberschreiben. Ausserdem braucht ein Task * einen Einsprungspunkt. */ struct task* init_task(void* entry, char *execName) { uint8_t* stack = pmm_alloc(); 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, .eip = (uint32_t) entry, //.cr3 = (uint32_t) create_task_paging(), /* Ring-3-Segmentregister */ .cs = 0x18 | 0x03, .ss = 0x20 | 0x03, /* IRQs einschalten (IF = 1) */ .eflags = 0x200, }; /* * 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(); task->cpu_state = state; task->next = first_task; task->pid = lastPid; task->running = true; task->executableName = execName; first_task = task; num_tasks++; lastPid++; return task; } void init_multitasking(struct multiboot_info* mb_info) { init_task(leerlauf_task, "Leerlauftask"); //init_task(get_rs232_input, "LF Serial Shell"); if (mb_info->mbs_mods_count > 0) { int i; for(i = 0; i < mb_info->mbs_mods_count; i++) { struct multiboot_module* modules = mb_info->mbs_mods_addr; load_elf((void*) modules[i].mod_start); } } } /* * 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 != NULL) { current_task->cpu_state = cpu; } /* * Naechsten Task auswaehlen. Wenn alle durch sind, geht es von vorne los */ current_task = getNextTask(current_task); /* Prozessorzustand des neuen Tasks aktivieren */ cpu = current_task->cpu_state; current_pid = current_task->pid; return cpu; } bool kill_task(int pid, struct cpu_state *cpu) { if(!is_running) return false; kprintf("Killing Task with PID %d\n", pid); task *last, *next, *current; current = first_task; next = current->next; last = NULL; while(current != NULL && current->pid != pid) { last = current; current = current->next; next = current->next; } if(current->pid == pid) { if(current->running == false) return false; if(current == first_task) first_task = current->next; current->running = false; pmm_free(current); last->next = next; num_tasks--; color = 0x04; kprintf("\n'%s' hat ein Problem festgestellt und musste beendet werden!\nSollte dieser Fehler oefter auftreten, treten Sie bitte mit dem Hersteller\ndieser Software in Verbindung.\nException: 0x%x(%d) Errorcode: 0x%x(%d)", current->executableName, cpu->intr, cpu->intr, cpu->error, cpu->error); color = 0x07; if(num_tasks <= 0) { kprintf("Oh nein!\n" "Wir haben keine Tasks mehr die den Prozessor beschäftigen könnten!\n" "Sogar der Leerlauftask musste schon beendet werden ...\n" "Absturz wird eingeleitet. Bitte warten ..."); return false; } struct cpu_state *temp = schedule(cpu); memcpy(cpu, temp, sizeof(struct cpu_state)); return true; } else return false; }