#include "Task.ns.h" #include #include #define INVALID_TASK_MAGIC 0xBEEFFEED #define TEMP_STACK_SIZE 256 //This must be big enough so that we can call all we need to call when a task finishes //From Task.wtf.asm extern "C" u32int read_eip(); extern "C" u32int idle_task(void*); namespace Task { SimpleList *processes = 0; SimpleList *threads = 0; SimpleList *currentThread = 0; Process* currentProcess = 0; SimpleList *idleThread = 0; u32int nextpid = 1; u32int temp_stack[TEMP_STACK_SIZE]; //Temporary stack used for finishing current thread Thread* currThread() { return currentThread->v(); } Process* currProcess() { return currentProcess; } Process* getKernelProcess() { if (processes == 0) PANIC("kko"); return processes->last()->v(); } void initialize(String cmdline, VirtualTerminal *vt) { asm volatile ("cli"); threads = 0; processes = 0; currentProcess = Process::createKernel(cmdline, vt); currentThread = threads; Thread* idle = new Thread(idle_task, 0, true); for (SimpleList *iter = threads; iter != 0; iter = iter->next()) { if (iter->v() == idle) { idleThread = iter; break; } } asm volatile ("sti"); } SimpleList *nextThread() { //Find next thread if ((u32int)currentThread == INVALID_TASK_MAGIC) { currentThread = threads; //This will happen when we come here just after current thread has finished } SimpleList *iter = currentThread; while (1) { iter = iter->next(); if (iter == 0) iter = threads; if (iter->v()->runnable() and iter->v() != idleThread->v()) { return iter; } if (iter == currentThread) break; } return idleThread; } void doSwitch() { if (currentThread == NULL or currentProcess == NULL) return; u32int esp, ebp, eip, cr3; asm volatile("mov %%esp, %0" : "=r"(esp)); asm volatile("mov %%ebp, %0" : "=r"(ebp)); eip = read_eip(); if (eip == 0x12345) { return; } //This will happen when we come here just after current thread has finished if ((u32int)currentThread != INVALID_TASK_MAGIC) currentThread->v()->setState(esp, ebp, eip); currentThread = nextThread(); Thread* t = currentThread->v(); currentProcess = t->getProcess(); esp = t->getEsp(); ebp = t->getEbp(); eip = t->getEip(); cr3 = currentProcess->getPagedir()->physicalAddr; asm volatile("cli"); t->setKernelStack(); asm volatile(" \ mov %0, %%ebp; \ mov %1, %%esp; \ mov %2, %%ecx; \ mov %3, %%cr3; \ mov $0x12345, %%eax; \ jmp *%%ecx;" : : "r"(ebp), "r"(esp), "r"(eip), "r"(cr3)); } void triggerSwitch() { asm volatile("int $65"); } u32int nextPid() { return nextpid++; } bool IRQwakeup(u8int irq) { bool r = false; for (SimpleList *iter = threads; iter != 0; iter = iter->next()) { r = r or iter->v()->irqHappens(irq); } return r; } void allocKernelPageTable(u32int id, page_table_t *table, u32int tablePhys) { kernelPageDirectory->tables[id] = table; kernelPageDirectory->tablesPhysical[id] = tablePhys; if (id < 768) return; //this would be a BUG for (SimpleList *iter = processes; iter != 0; iter = iter->next()) { iter->v()->getPagedir()->tables[id] = table; iter->v()->getPagedir()->tablesPhysical[id] = tablePhys; } } void currThreadExitProceed(u32int errcode) { currentThread->v()->finish(errcode); currentThread = (SimpleList*)INVALID_TASK_MAGIC; doSwitch(); //Normally never come back from here } void currentThreadExits(u32int errcode) { //Call currThreadExitProceed with a working stack (we use temp_stack) asm volatile("cli"); u32int* stack = &temp_stack[TEMP_STACK_SIZE]; stack--; *stack = errcode; stack--; *stack = 0; u32int esp = (u32int)(stack), ebp = (u32int)(stack + 1), eip = (u32int)currThreadExitProceed; asm volatile(" \ mov %0, %%ebp; \ mov %1, %%esp; \ mov %2, %%ecx; \ mov %3, %%cr3; \ jmp *%%ecx;" : : "r"(ebp), "r"(esp), "r"(eip), "r"(kernelPageDirectory->physicalAddr)); } void registerThread(Thread* t) { unregisterThread(t); //...// threads = threads->cons(t); } void unregisterThread(Thread* t) { if (threads == 0) return; //Tasking not yet initialized threads = threads->removeOnce(t); } void registerProcess(Process* p) { unregisterProcess(p); //...// processes = processes->cons(p); } void unregisterProcess(Process* p) { if (processes == 0) return; //Tasking not yet initialized processes = processes->removeOnce(p); } }