summaryrefslogtreecommitdiff
path: root/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'kernel')
-rw-r--r--kernel/asm.s120
-rw-r--r--kernel/boot.s38
-rw-r--r--kernel/kmain.c4
-rw-r--r--kernel/sched.c151
-rw-r--r--kernel/sys.c14
-rw-r--r--kernel/timer.s25
-rw-r--r--kernel/traps.s15
7 files changed, 249 insertions, 118 deletions
diff --git a/kernel/asm.s b/kernel/asm.s
index 4abe607..0bf9067 100644
--- a/kernel/asm.s
+++ b/kernel/asm.s
@@ -1,60 +1,76 @@
+global clear_tss
global switch_to
+global set_tss
+extern cstate
extern ctask
-extern tss
+extern gdt
+extern save_state
+; void switch_to(int n, struct task_struct *task);
switch_to:
push ebp
mov ebp, esp
- mov eax, [ebp+8]
- mov [ctask], eax
- mov esi, [ebp+12]
- mov ecx, 13
-.loop:
- lodsd
- push eax
- dec ecx
- jz .end
- jmp .loop
-.end:
- mov ax, 0x23
- mov ds, ax
- mov es, ax
- mov fs, ax
- mov gs, ax
- popa
- iret
+ ; abort if we're switching to the current task
+ mov ebx, [ctask]
+ cmp ebx, [ebp+12]
+ jne .skip
+ pop ebp
+ ret
+.skip:
+ ; clear the busy flag in the current TSS
+ mov eax, 0
+ str ax
+ add ax, gdt+5
+ mov byte [eax], 0x89
+ ; set the current TSS to null so it won't be overwritten by the switch
+ mov ax, 0
+ ltr ax
+ ; copy the saved state into the previous TSS
+ call save_state
+ ; update ctask
+ mov ebx, [ebp+12]
+ mov [ctask], ebx
+ ; calculate the task segment index and jump to it
+ mov ebx, [ebp+8]
+ add ebx, 5
+ shl ebx, 3
+ mov [.tmp+4], bx
+ jmp far [.tmp]
+.tmp:
+ dq 0
-; uint32_t ss;
-; uint32_t esp;
-; uint32_t eflags;
-; uint32_t cs;
-; uint32_t eip;
-; uint32_t eax;
-; uint32_t ecx;
-; uint32_t edx;
-; uint32_t ebx;
-; uint32_t esp_garbage;
-; uint32_t ebp;
-; uint32_t esi;
-; uint32_t edi;
+; void set_tss(unsigned int n, void *tss);
+set_tss:
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov eax, [ebp+12]
+ mov ebx, [ebp+8]
+ shl ebx, 3
+ add ebx, gdt+40
+ mov [ebx+2], ax
+ shr eax, 16
+ mov [ebx+4], al
+ mov [ebx+7], ah
+ mov eax, 103 ; limit - 1
+ mov [ebx], ax
+ shr eax, 16
+ and al, 0x0F
+ mov [ebx+6], al
+ mov byte [ebx+5], 0x89
+ pop ebx
+ pop ebp
+ ret
-; switch_to:
- ; push ebp
- ; mov ebp, esp
- ; cli
- ; mov ax, 0x23
- ; mov ds, ax
- ; mov es, ax
- ; mov fs, ax
- ; mov gs, ax
- ; mov eax, esp
- ; ; save ESP in the TSS
- ; mov [tss+4], eax
- ; push dword 0x23
- ; push dword 0x00180000
- ; pushf
- ; push dword 0x1B
- ; push dword 0x00100000
- ; iret
- ; pop ebp
- ; ret
+; void clear_tss(unsigned int n);
+clear_tss:
+ push ebp
+ mov ebp, esp
+ push ebx
+ mov ebx, [ebp+8]
+ shl ebx, 3
+ add ebx, gdt+40
+ mov byte [ebx+5], 0
+ pop ebx
+ pop ebp
+ ret
diff --git a/kernel/boot.s b/kernel/boot.s
index 9d948cf..98732f6 100644
--- a/kernel/boot.s
+++ b/kernel/boot.s
@@ -2,7 +2,6 @@ global gdt
global idt
global kboot
global register_isr
-global tss
extern kmain
extern paging_init
extern syscall_init
@@ -23,7 +22,7 @@ kboot:
cli
; put the stack pointer near the end of conventional memory
; WARNING: don't change this without changing the corresponding
- ; entry in the TSS
+ ; entries in the TSS constructor in sched.c
mov esp, 0x80000
; setup descriptor tables
call flush_gdt
@@ -37,20 +36,6 @@ kboot:
cli
hlt
-tss:
- dd 0
- dd 0x80000 ; kernel stack pointer
- dd 0x10 ; kernel stack segment
- times 60 db 0
- dd 0x13 ; ES segment
- dd 0x0B ; CS segment
- dd 0x13 ; SS segment
- dd 0x13 ; DS segment
- dd 0x13 ; FS segment
- dd 0x13 ; GS segment
- times 8 db 0
-.end:
-
gdt:
; null descriptor
dq 0
@@ -82,9 +67,8 @@ gdt:
db 0xF2
db 0xCF
db 0x00
- ; task state segment
-.tss:
- dq 0 ; we initialize this later
+ ; empty TSS slots for our C scheduler
+ times 64 dq 0
.end:
gdtp:
@@ -94,19 +78,6 @@ gdtp:
flush_gdt:
push ebp
mov ebp, esp
- ; initialize the TSS entry
- mov eax, tss
- mov [gdt.tss+2], ax
- shr eax, 16
- mov [gdt.tss+4], al
- mov [gdt.tss+7], ah
- mov eax, (tss.end-tss-1)
- mov [gdt.tss], ax
- shr eax, 16
- and al, 0x0F
- mov [gdt.tss+6], al
- mov al, 0xE9
- mov [gdt.tss+5], al
; now, load the GDT
lgdt [gdtp]
mov ax, 0x10
@@ -117,9 +88,6 @@ flush_gdt:
mov ss, ax
jmp 0x08:.end
.end:
- ; initialize the task state register
- mov ax, 0x002B
- ltr ax
pop ebp
ret
diff --git a/kernel/kmain.c b/kernel/kmain.c
index 5b2fe91..6b550b7 100644
--- a/kernel/kmain.c
+++ b/kernel/kmain.c
@@ -1,9 +1,7 @@
#include <kernel/con.h>
-#include <kernel/memory.h>
#include <kernel/sched.h>
#include <kernel/sys.h>
#include <stdint.h>
-#include <sys/types.h>
void kmain(void) {
con_init();
@@ -11,5 +9,5 @@ void kmain(void) {
printk("Kernel booting...\n");
printk("Kernel booted!\n\n");
- userspace_init();
+ sched_init();
}
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]);
+ }
}
diff --git a/kernel/sys.c b/kernel/sys.c
index 3748e2b..8c33fdf 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -1,7 +1,9 @@
#include <errno.h>
#include <kernel/con.h>
+#include <kernel/sched.h>
#include <stdint.h>
#include <time.h>
+#include <unistd.h>
extern uint32_t ticks;
@@ -13,6 +15,18 @@ time_t sys_time(void) {
return ticks / 100;
}
+pid_t sys_getpid(void) {
+ return ctask->pid;
+}
+
+void *sys_getpdir(void) {
+ uint32_t pdir;
+
+ __asm__ ("mov %%cr3, %%eax" : "=a" (pdir));
+
+ return (void*) pdir;
+}
+
int sys_dummy(void) {
return -ENOSYS;
}
diff --git a/kernel/timer.s b/kernel/timer.s
index 3723782..c84a847 100644
--- a/kernel/timer.s
+++ b/kernel/timer.s
@@ -1,15 +1,40 @@
global ticks
global timer_init
+extern cstate
extern register_isr
+extern reschedule
ticks: dd 0
tick_handler:
+ pusha
+ ; save the data segment selectors
+ mov ax, ds
push ax
+ ; switch to kernel data segments
+ mov ax, 0x10
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ ; save a pointer to the state information
+ mov [cstate], esp
+
+ ; handle the timer tick
inc dword [ticks]
mov al, 0x20
out 0x20, al
+
+ ; call the scheduler
+ call reschedule
+
+ ; restore the data segment selectors
pop ax
+ mov ds, ax
+ mov es, ax
+ mov fs, ax
+ mov gs, ax
+ popa
iret
timer_init:
diff --git a/kernel/traps.s b/kernel/traps.s
index 15e2640..e084ac8 100644
--- a/kernel/traps.s
+++ b/kernel/traps.s
@@ -8,7 +8,7 @@ global traps_init
extern call_table
extern idt
extern panic
-extern printf
+extern printk
extern register_isr
%macro SAVE 0
@@ -190,7 +190,16 @@ exc_stackf:
exc_gprot:
SAVE_ERR
+
+ push ebx
+ push .fmt
+ call printk
+ add esp, 8
+ call panic
+
RESTORE_ERR
+.fmt:
+ db "General Protection Fault (0x%08x)", 10, 0
exc_pagef:
SAVE_ERR
@@ -199,8 +208,8 @@ exc_pagef:
mov ebx, cr2
push ebx
push .fmt
- call printf
- add esp, 8
+ call printk
+ add esp, 12
call panic
RESTORE_ERR