diff options
Diffstat (limited to 'kernel/sched.c')
| -rw-r--r-- | kernel/sched.c | 151 |
1 files changed, 126 insertions, 25 deletions
diff --git a/kernel/sched.c b/kernel/sched.c index 3e25de0..dd75d47 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -1,10 +1,17 @@ #include <asm/system.h> -#include <kernel/con.h> #include <kernel/memory.h> #include <kernel/sched.h> #include <string.h> #include <sys/types.h> +/* + * WARNING! + * don't change this without also updating + * the number of TSS descriptors in the GDT + * (located in boot.s) + */ +#define NRTASKS 64 + #define USRSTART ((void*) 0x40000000) #define pages(n) \ @@ -23,9 +30,29 @@ extern char _usrbin_start; extern char _usrbin_size; +struct task_state { + uint16_t ds; + uint32_t edi; + uint32_t esi; + uint32_t ebp; + uint32_t esp_garbage; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; +} __attribute__((packed)); + struct task_struct *ctask; +struct task_state *cstate; -static struct task_struct task; +static struct task_struct tasks[NRTASKS]; + +static pid_t nextpid; static inline void empty_table(void *t) { int i; @@ -34,19 +61,41 @@ static inline void empty_table(void *t) { ((uint32_t*) t)[i] = 0; } -void userspace_init(void) { +struct task_struct *create_proc(void *bin, size_t len) { int i, j; int c; size_t totpages, npages, ntables; void *p, *page, *tab, *map; void *pdir, *stackt, *stackp; + struct task_struct *task = NULL; - size_t usrsize = (size_t) &_usrbin_size; - - npages = pages(usrsize); - ntables = tables(pages(usrsize)); + npages = pages(len); + ntables = tables(pages(len)); totpages = npages + ntables + 3; + /* find an unused task structure */ + for(i = 0; i < NRTASKS; i++) { + if(!tasks[i].pid) { + task = &tasks[i]; + /* update the GDT */ + set_tss(i, &tasks[i].state); + break; + } + } + if(task == NULL) + return NULL; + + /* find an unused PID */ + for(i = 0; i < NRTASKS; i++) { + if(tasks[i].pid == nextpid) { + /* TODO: handle PID exhaustion */ + nextpid++; + if(nextpid == 0) + nextpid++; + i = 0; + } + } + /* here we allocate pages to setup the process' * address space. in addition to the pages that * will hold the binary image, the following @@ -57,19 +106,12 @@ void userspace_init(void) { * - stack table (1 page) */ p = alloc_physical_pages(totpages); - printk("Allocating %x pages for userspace process\n", totpages); - if(p == NULL) { - printk("Failed to allocate memory for userspace!\n"); - return; - } + if(p == NULL) + return NULL; getpage(pdir, p); getpage(stackt, p); getpage(stackp, p); - printk(" Page directory: 0x%08x\n", (uint32_t) pdir); - printk(" Stack table: 0x%08x\n", (uint32_t) stackt); - printk(" Stack page: 0x%08x\n", (uint32_t) stackp); - printk(" Page tables:\n"); /* populate the page directory */ c = npages; @@ -78,7 +120,6 @@ void userspace_init(void) { for(i = 0; i < ntables; i++) { /* add the table entry to the directory */ getpage(tab, p); - printk(" 0x%08x\n", (uint32_t) tab); map = map_page(pdir); ((uint32_t*) map)[i + (PGENT / 4)] = (uint32_t) tab | 0x007; @@ -109,23 +150,83 @@ void userspace_init(void) { __asm__ volatile ("mov %%eax, %%cr3" :: "a" (pdir)); - memcpy(USRSTART, &_usrbin_start, usrsize); + /* load in the user binary */ + memcpy(USRSTART, bin, len); /* * here we initialize the task struct. * currently, we only setup state information * necessary to begin execution. */ - memset(&task, 0, sizeof(task)); - task.state.cs = 0x1B; - task.state.ss = 0x23; - task.state.eip = (uint32_t) USRSTART; - task.state.esp = 0xFFFFFFFF; + memset(task, 0, sizeof(struct task_struct)); + task->pid = nextpid; + task->state.cr3 = (uint32_t) pdir; + task->state.cs = 0x1B; + task->state.ds = 0x23; + task->state.es = 0x23; + task->state.fs = 0x23; + task->state.gs = 0x23; + task->state.ss = 0x23; + task->state.eip = (uint32_t) USRSTART; + task->state.esp = 0xFFFFFFFF; + task->state.esp0 = 0x80000; + task->state.ss0 = 0x10; __asm__ ( "pushf\n" \ "pop %%eax" \ - : "=a" (task.state.eflags) \ + : "=a" (task->state.eflags) \ ::); - switch_to(&task, &task.state); + return task; +} + +void sched_init(void) { + int i; + struct task_struct *task; + + memset(&tasks, 0, sizeof(tasks)); + for(i = 0; i < NRTASKS; i++) + clear_tss(i); + + nextpid = 1; + ctask = NULL; + cstate = NULL; + + create_proc(&_usrbin_start, (size_t) &_usrbin_size); + create_proc(&_usrbin_start, (size_t) &_usrbin_size); + + switch_to(0, &tasks[0]); +} + +void save_state(void) { + if(ctask == NULL || cstate == NULL) + return; + + ctask->state.eax = cstate->eax; + ctask->state.ebx = cstate->ebx; + ctask->state.ecx = cstate->ecx; + ctask->state.edx = cstate->edx; + ctask->state.esi = cstate->esi; + ctask->state.edi = cstate->edi; + ctask->state.esp = cstate->esp; + ctask->state.ebp = cstate->ebp; + ctask->state.cs = cstate->cs; + ctask->state.ds = cstate->ds; + ctask->state.es = cstate->ds; + ctask->state.fs = cstate->ds; + ctask->state.gs = cstate->ds; + ctask->state.ss = cstate->ss; + ctask->state.eflags = cstate->eflags; + ctask->state.eip = cstate->eip; +} + +void reschedule(void) { + if(ctask == NULL) + return; + + if(ctask == &tasks[0]) { + switch_to(1, &tasks[1]); + } else { + switch_to(0, &tasks[0]); + } } |
