summaryrefslogtreecommitdiff
path: root/kernel/sched.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/sched.c')
-rw-r--r--kernel/sched.c151
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]);
+ }
}