diff options
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/asm.s | 120 | ||||
| -rw-r--r-- | kernel/boot.s | 38 | ||||
| -rw-r--r-- | kernel/kmain.c | 4 | ||||
| -rw-r--r-- | kernel/sched.c | 151 | ||||
| -rw-r--r-- | kernel/sys.c | 14 | ||||
| -rw-r--r-- | kernel/timer.s | 25 | ||||
| -rw-r--r-- | kernel/traps.s | 15 |
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 |
