# HG changeset patch # User John Tsiombikas # Date 1312688520 -10800 # Node ID fa65b4f453667af163c298f6af3ebf1d15cd960d # Parent b1e8c8251884d74ebdc98a55c00c7fd3c3d69b76 picking this up again, let's fix it diff -r b1e8c8251884 -r fa65b4f45366 .hgignore --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/.hgignore Sun Aug 07 06:42:00 2011 +0300 @@ -0,0 +1,5 @@ +\.d$ +\.o$ +\.swp$ +^kernel.elf$ +^link.map$ diff -r b1e8c8251884 -r fa65b4f45366 debug --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/debug Sun Aug 07 06:42:00 2011 +0300 @@ -0,0 +1,4 @@ +#!/bin/sh + +qemu -kernel kernel.elf -s -S & +gdb diff -r b1e8c8251884 -r fa65b4f45366 src/config.h --- a/src/config.h Mon Aug 01 06:45:29 2011 +0300 +++ b/src/config.h Sun Aug 07 06:42:00 2011 +0300 @@ -7,4 +7,7 @@ #define TIMESLICE 100 #define TIMESLICE_TICKS (TIMESLICE * TICK_FREQ_HZ / 1000) +/* allow automatic user stack growth by at most 1024 pages at a time (4mb) */ +#define USTACK_MAXGROW 1024 + #endif /* _CONFIG_H_ */ diff -r b1e8c8251884 -r fa65b4f45366 src/intr.c --- a/src/intr.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/intr.c Sun Aug 07 06:42:00 2011 +0300 @@ -48,6 +48,8 @@ /* table of handler functions for all interrupts */ static intr_func_t intr_func[256]; +static struct intr_frame *cur_intr_frame; + void init_intr(void) { @@ -74,6 +76,14 @@ init_pic(IRQ_OFFSET); } +/* retrieve the current interrupt frame. + * returns 0 when called during kernel init. + */ +struct intr_frame *get_intr_frame(void) +{ + return cur_intr_frame; +} + /* set an interrupt handler function for a particular interrupt */ void interrupt(int intr_num, intr_func_t func) { @@ -86,8 +96,10 @@ */ void dispatch_intr(struct intr_frame frm) { + cur_intr_frame = &frm; + if(intr_func[frm.inum]) { - intr_func[frm.inum](frm.inum, &frm); + intr_func[frm.inum](frm.inum); } else { if(frm.inum < 32) { panic("unhandled exception %d, error code: %d\n", frm.inum, frm.err); diff -r b1e8c8251884 -r fa65b4f45366 src/intr.h --- a/src/intr.h Mon Aug 01 06:45:29 2011 +0300 +++ b/src/intr.h Sun Aug 07 06:42:00 2011 +0300 @@ -28,11 +28,13 @@ -typedef void (*intr_func_t)(int, struct intr_frame *frm); +typedef void (*intr_func_t)(int); void init_intr(void); +struct intr_frame *get_intr_frame(void); + void interrupt(int intr_num, intr_func_t func); /* defined in intr-asm.S */ diff -r b1e8c8251884 -r fa65b4f45366 src/klibc/assert.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/klibc/assert.h Sun Aug 07 06:42:00 2011 +0300 @@ -0,0 +1,11 @@ +#ifndef ASSERT_H_ +#define ASSERT_H_ + +#include "panic.h" + +#define assert(x) \ + if(!(x)) { \ + panic("Kernel assertion failed: " #x "\n"); \ + } + +#endif /* ASSERT_H_ */ diff -r b1e8c8251884 -r fa65b4f45366 src/main.c --- a/src/main.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/main.c Sun Aug 07 06:42:00 2011 +0300 @@ -39,11 +39,10 @@ init_timer(); init_rtc(); - /* initialization complete, enable interrupts */ - enable_intr(); - + /* create the first process and switch to it */ init_proc(); + /* XXX unreachable */ for(;;) { halt_cpu(); diff -r b1e8c8251884 -r fa65b4f45366 src/proc.c --- a/src/proc.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/proc.c Sun Aug 07 06:42:00 2011 +0300 @@ -1,4 +1,6 @@ +#include #include +#include #include "proc.h" #include "tss.h" #include "vm.h" @@ -8,6 +10,7 @@ #include "syscall.h" #include "sched.h" +#define FLAGS_INTR_BIT 9 /* defined in test_proc.S */ void test_proc(void); @@ -39,6 +42,8 @@ img_start = (void*)PAGE_TO_ADDR(img_start_pg); memcpy(img_start, test_proc, proc_size_pg * PGSIZE); + printf("copied init process at: %x\n", (unsigned int)img_start); + /* instruction pointer at the beginning of the process image */ proc[1].ctx.instr_ptr = (uint32_t)img_start; @@ -49,6 +54,9 @@ } proc[1].ctx.stack_ptr = PAGE_TO_ADDR(stack_pg) + PGSIZE; + proc[1].stack_end = KMEM_START; + proc[1].stack_start = KMEM_START - PGSIZE; + /* create the virtual address space for this process */ proc[1].ctx.pgtbl_paddr = clone_vm(); @@ -60,7 +68,7 @@ pgfree(stack_pg, 1); /* add it to the scheduler queues */ - //add_proc(1, STATE_RUNNING); + add_proc(1, STATE_RUNNING); /* switch to the initial process, this never returns */ context_switch(1); @@ -69,26 +77,33 @@ void context_switch(int pid) { + struct context *ctx; struct intr_frame ifrm; - struct context *ctx = &proc[pid].ctx; + struct intr_frame *cur_frame = get_intr_frame(); + assert(0); + if(cur_pid == pid) { + assert(cur_frame); + intr_ret(*cur_frame); + } + + ctx = &proc[pid].ctx; cur_pid = pid; ifrm.inum = ifrm.err = 0; ifrm.regs = ctx->regs; - ifrm.eflags = ctx->flags | (1 << 9); + ifrm.eflags = ctx->flags | (1 << FLAGS_INTR_BIT); ifrm.eip = ctx->instr_ptr; ifrm.cs = selector(SEGM_KCODE, 0); /* XXX change this when we setup the TSS */ - ifrm.esp = 0;/*ctx->stack_ptr; /* this will only be used when we switch to userspace */ - ifrm.regs.esp = ctx->stack_ptr; /* ... until then... */ - ifrm.ss = 0;/*selector(SEGM_KDATA, 0); /* XXX */ + /*ifrm.regs.esp = ctx->stack_ptr;*/ /* ... until then... */ + ifrm.esp = ctx->stack_ptr; /* this will only be used when we switch to userspace */ + ifrm.ss = selector(SEGM_KDATA, 0); /* switch to the vm of the process */ set_pgdir_addr(ctx->pgtbl_paddr); - intr_ret(ifrm); } diff -r b1e8c8251884 -r fa65b4f45366 src/proc.h --- a/src/proc.h Mon Aug 01 06:45:29 2011 +0300 +++ b/src/proc.h Sun Aug 07 06:42:00 2011 +0300 @@ -27,6 +27,12 @@ enum proc_state state; int ticks_left; + + /* extends of the process heap, increased by sbrk */ + + /* first page of the user stack, extends up to KMEM_START */ + int stack_start_pg; + struct context ctx; struct process *next, *prev; /* for the scheduler queues */ diff -r b1e8c8251884 -r fa65b4f45366 src/sched.c --- a/src/sched.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/sched.c Sun Aug 07 06:42:00 2011 +0300 @@ -21,17 +21,18 @@ void schedule(void) { + disable_intr(); + if(EMPTY(runq)) { /* idle "process". * make sure interrupts are enabled before halting */ enable_intr(); halt_cpu(); + printf("fuck you!\n"); /* this won't return, it'll just wake up in an interrupt later */ } - disable_intr(); - /* if the current process exhausted its timeslice, * move it to the back of the queue. */ @@ -54,11 +55,13 @@ { int istate; struct proc_list *q; - struct process *proc = get_process(pid); + struct process *proc; istate = get_intr_state(); disable_intr(); + proc = get_process(pid); + q = state == STATE_RUNNING ? &runq : &waitq; ins_back(q, proc); diff -r b1e8c8251884 -r fa65b4f45366 src/syscall.c --- a/src/syscall.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/syscall.c Sun Aug 07 06:42:00 2011 +0300 @@ -7,7 +7,7 @@ static int (*sys_func[NUM_SYSCALLS])(); -static void syscall(int inum, struct intr_frame *frm); +static void syscall(int inum); static int sys_exit(int status); static int sys_hello(void); @@ -22,9 +22,13 @@ interrupt(SYSCALL_INT, syscall); } -static void syscall(int inum, struct intr_frame *frm) +static void syscall(int inum) { - int idx = frm->regs.eax; + struct intr_frame *frm; + int idx; + + frm = get_intr_frame(); + idx = frm->regs.eax; if(idx < 0 || idx >= NUM_SYSCALLS) { printf("invalid syscall: %d\n", idx); diff -r b1e8c8251884 -r fa65b4f45366 src/term.c --- a/src/term.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/term.c Sun Aug 07 06:42:00 2011 +0300 @@ -1,6 +1,7 @@ #include #include "term.h" #include "vid.h" +#include "intr.h" static int bg, fg = LTGRAY; static int cursor_x, cursor_y; @@ -32,6 +33,9 @@ */ int putchar(int c) { + int istate = get_intr_state(); + disable_intr(); + switch(c) { case '\n': cursor_y++; @@ -65,5 +69,7 @@ } set_cursor(cursor_x, cursor_y); + + set_intr_state(istate); return c; } diff -r b1e8c8251884 -r fa65b4f45366 src/vm.c --- a/src/vm.c Mon Aug 01 06:45:29 2011 +0300 +++ b/src/vm.c Sun Aug 07 06:42:00 2011 +0300 @@ -1,12 +1,13 @@ #include #include #include +#include +#include "config.h" #include "vm.h" -#include #include "intr.h" #include "mem.h" #include "panic.h" - +#include "proc.h" #define IDMAP_START 0xa0000 @@ -37,7 +38,7 @@ uint32_t get_fault_addr(void); static void coalesce(struct page_range *low, struct page_range *mid, struct page_range *high); -static void pgfault(int inum, struct intr_frame *frm); +static void pgfault(int inum); static struct page_range *alloc_node(void); static void free_node(struct page_range *node); @@ -457,11 +458,43 @@ } } -static void pgfault(int inum, struct intr_frame *frm) +static void pgfault(int inum) { + struct intr_frame *frm = get_intr_frame(); + uint32_t fault_addr = get_fault_addr(); + + /* the fault occured in user space */ + if(frm->esp < KMEM_START + 1) { + int fault_page = ADDR_TO_PAGE(fault_addr); + struct process *proc = get_current_proc(); + assert(proc); + + printf("DBG: page fault in user space\n"); + + if(frm->err & PG_PRESENT) { + /* it's not due to a missing page, just panic */ + goto unhandled; + } + + /* detect if it's an automatic stack growth deal */ + if(fault_page < proc->stack_start_pg && proc->stack_start_pg - fault_page < USTACK_MAXGROW) { + int num_pages = proc->stack_start_pg - fault_page; + printf("growing user (%d) stack by %d pages\n", proc->id, num_pages); + + if(pgalloc_vrange(fault_page, num_pages) != fault_page) { + printf("failed to allocate VM for stack growth\n"); + /* TODO: in the future we'd SIGSEGV the process here, for now just panic */ + goto unhandled; + } + proc->stack_start_pg = fault_page; + + return; + } + } + +unhandled: printf("~~~~ PAGE FAULT ~~~~\n"); - - printf("fault address: %x\n", get_fault_addr()); + printf("fault address: %x\n", fault_addr); if(frm->err & PG_PRESENT) { if(frm->err & 8) {