#include <ubixos/kpanic.h> #include <ubixos/spinlock.h> #include <ubixos/sched.h> #include <ubixos/vitals.h> #include <vfs/mount.h> #include <lib/kmalloc.h> #include <lib/kprintf.h> #include <vmm/vmm.h> #include <sys/gdt.h> #include <sys/idt.h> #include <isa/8259.h> #include <string.h> #include <assert.h> #include <ubixos/spinlock.h> static kTask_t *taskList = NULL; static uInt32 nextID = -1; kTask_t *_current = NULL; kTask_t *_usedMath = NULL; static spinLock_t schedulerSpinLock = SPIN_LOCK_INITIALIZER; static spinLock_t nextIDSpinLock = SPIN_LOCK_INITIALIZER; void LoadTaskState(uInt16 selector) { //asm ("ltr %0": : "m" (selector)); return; } uInt16 StoreTaskState() { uInt16 selector = 0x0; //asm volatile("str %0": : "r" (selector)); return selector; } void Switch(uInt16 selector) { asm ("lcall %0": : "m" (selector)); } uInt16 kernel = 1; void SendTaskToProcessor(kTask_t *task, kProcessor *cpu) { uInt32 memAddr = 0x0; uInt16 current = 2; _current = task; memAddr = (uInt32)&(task->tss); ubixGDT[4].descriptor.baseLow = (memAddr & 0xFFFF); ubixGDT[4].descriptor.baseMed = ((memAddr >> 16) & 0xFF); ubixGDT[4].descriptor.baseHigh = (memAddr >> 24); ubixGDT[4].descriptor.access = '\x89'; /* enable interrupts, particularly the timer interrupt */ //irqEnable(0x0); //kernel = StoreTaskState(); //LoadTaskState(kernel); //Switch(kernel); asm("ljmp $0x20,$0\n"); kprintf("WOOT!!\n"); while (1); /* no interrupts can occur at the dispatch level */ irqDisable(0x0); return; } /************************************************************************ Function: int sched_init() Description: This function is used to enable the kernel scheduler Notes: 02/20/2004 - Approved for quality 08/07/2005 - begun rewrite as non-reentrant (Stephen A. Hodges) ************************************************************************/ int sched_init() { taskList = (kTask_t *)kmalloc(sizeof(kTask_t)); if(taskList == 0x0) kpanic("Unable to create task list"); taskList->id = nextID++; _current = NULL; taskList->first = NULL; taskList->last = NULL; taskList->next = NULL; taskList->prev = NULL; /* Print out information on scheduler */ kprintf("sched0 - Address: [0x%X]\n", taskList); /* Return so we know everything went well */ return(0x0); } void sched() { kTask_t *tmpTask = NULL; kTask_t *delTask = NULL; kProcessor *cpu = NULL; /* no interrupts can occur at the dispatch level */ irqDisable(0x0); /* block reentrant schedule calls (there should be none anyways) */ spinLock(&schedulerSpinLock); while(1) { /* traverse the task queue */ for (tmpTask = taskList->first ;tmpTask != NULL ; tmpTask = tmpTask->next) { switch(tmpTask->state) { case READY: tmpTask->state = RUNNING; kprintf("sending task to CPU\n"); SendTaskToProcessor(tmpTask, cpu); tmpTask->state = WAIT; break; case WAIT: /* TODO: Sort priority list */ tmpTask->state = READY; break; case FORK: tmpTask->state = NEW; break; case NEW: /* TODO: Add to wait list */ tmpTask->state = WAIT; break; case RUNNING: break; case IDLE: SendTaskToProcessor(tmpTask, cpu); break; case DEAD: delTask = tmpTask; if (delTask->prev != 0x0) delTask->prev->next = delTask->next; if (tmpTask->next != 0x0) delTask->next->prev = delTask->prev; if (taskList == delTask) taskList = delTask->next; vmmFreeProcessPages(delTask->id); if (delTask->imageFd != 0x0) fclose(delTask->imageFd); kfree(delTask); break; default: kpanic("Unknown task state [%d] for task [%d]!\n", tmpTask->state, tmpTask->id); break; } } /* finished all tasks */ } return; } kTask_t *schedNewTask() { kTask_t *tmpTask = (kTask_t *)kmalloc(sizeof(kTask_t)); if (tmpTask == NULL) { kprintf("Error: schedNewTask() - kmalloc failed trying to initialize a new task struct\n"); return NULL; } if(taskList->first == NULL) { taskList->first = tmpTask; taskList->last = tmpTask; } memset(tmpTask,0x0,sizeof(kTask_t)); /* Filling in tasks attrs */ tmpTask->usedMath = 0x0; tmpTask->state = NEW; spinLock(&schedulerSpinLock); tmpTask->id = nextID++; taskList->last->next = tmpTask; tmpTask->next = NULL; tmpTask->prev = taskList->last; taskList->last = tmpTask; spinUnlock(&schedulerSpinLock); return(tmpTask); } kTask_t * schedFindTask(uInt32 id) { kTask_t *tmpTask = 0x0; spinLock(&schedulerSpinLock); for (tmpTask = taskList; tmpTask; tmpTask = tmpTask->next) { if (tmpTask->id == id) return(tmpTask); } spinUnlock(&schedulerSpinLock); return(0x0); } /************************************************************************ Function: void schedEndTask() Description: This function will end a task Notes: 02/20/2004 - Approved for quality ************************************************************************/ void sched_yield() { kpanic("sched_yield() is obsolete!\n"); } /************************************************************************ Function: int sched_setStatus(pidType pid,tState state) Description: Change the tasks status Notes: ************************************************************************/ int sched_setStatus(pidType pid,tState state) { kTask_t *tmpTask = schedFindTask(pid); if (tmpTask == 0x0) return(0x1); tmpTask->state = state; return(0x0); } int sched_setStatus2(kTask_t *task, tState state) { if(task == 0x0) return 0x1; task->state = state; return 0x0; } /*** END ***/