# HG changeset patch # User John Tsiombikas # Date 1312170329 -10800 # Node ID b1e8c8251884d74ebdc98a55c00c7fd3c3d69b76 # Parent 1d8877d12de09ef9f3b433ffc9248262811df05a lalalala diff -r 1d8877d12de0 -r b1e8c8251884 run --- a/run Sat Jul 30 07:35:53 2011 +0300 +++ b/run Mon Aug 01 06:45:29 2011 +0300 @@ -1,3 +1,3 @@ #!/bin/sh -qemu -kernel kernel.elf -soundhw pcspk +qemu -kernel kernel.elf -soundhw pcspk $* diff -r 1d8877d12de0 -r b1e8c8251884 src/config.h --- a/src/config.h Sat Jul 30 07:35:53 2011 +0300 +++ b/src/config.h Mon Aug 01 06:45:29 2011 +0300 @@ -4,4 +4,7 @@ /* frequency of generated timer ticks in hertz */ #define TICK_FREQ_HZ 250 +#define TIMESLICE 100 +#define TIMESLICE_TICKS (TIMESLICE * TICK_FREQ_HZ / 1000) + #endif /* _CONFIG_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/intr.c --- a/src/intr.c Sat Jul 30 07:35:53 2011 +0300 +++ b/src/intr.c Mon Aug 01 06:45:29 2011 +0300 @@ -38,7 +38,6 @@ static void init_pic(int offset); static void gate_desc(desc_t *desc, uint16_t sel, uint32_t addr, int dpl, int type); static void set_intr_entry(int num, void (*handler)(void)); -static void end_of_irq(int irq); /* defined in intr-asm.S */ void set_idt(uint32_t addr, uint16_t limit); @@ -88,7 +87,7 @@ void dispatch_intr(struct intr_frame frm) { if(intr_func[frm.inum]) { - intr_func[frm.inum](frm.inum, frm.err); + intr_func[frm.inum](frm.inum, &frm); } else { if(frm.inum < 32) { panic("unhandled exception %d, error code: %d\n", frm.inum, frm.err); @@ -141,7 +140,7 @@ gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type); } -static void end_of_irq(int irq) +void end_of_irq(int irq) { if(irq > 7) { outb(OCW2_EOI, PIC2_CMD); diff -r 1d8877d12de0 -r b1e8c8251884 src/intr.h --- a/src/intr.h Sat Jul 30 07:35:53 2011 +0300 +++ b/src/intr.h Mon Aug 01 06:45:29 2011 +0300 @@ -28,7 +28,7 @@ -typedef void (*intr_func_t)(int, uint32_t); +typedef void (*intr_func_t)(int, struct intr_frame *frm); void init_intr(void); @@ -41,4 +41,6 @@ void intr_ret(struct intr_frame ifrm); +void end_of_irq(int irq); + #endif /* INTR_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/proc.c --- a/src/proc.c Sat Jul 30 07:35:53 2011 +0300 +++ b/src/proc.c Mon Aug 01 06:45:29 2011 +0300 @@ -5,6 +5,8 @@ #include "segm.h" #include "intr.h" #include "panic.h" +#include "syscall.h" +#include "sched.h" /* defined in test_proc.S */ @@ -18,50 +20,50 @@ { int proc_size_pg, img_start_pg, stack_pg; void *img_start; - cur_pid = -1; + cur_pid = 0; + + init_syscall(); /* prepare the first process */ + proc[1].id = 1; + proc[1].parent = 0; /* allocate a chunk of memory for the process image * and copy the code of test_proc there. * (should be mapped at a fixed address) */ - /*proc_size_pg = (test_proc_end - test_proc) / PGSIZE + 1; + proc_size_pg = (test_proc_end - test_proc) / PGSIZE + 1; if((img_start_pg = pgalloc(proc_size_pg, MEM_USER)) == -1) { panic("failed to allocate space for the init process image\n"); } img_start = (void*)PAGE_TO_ADDR(img_start_pg); - memcpy(img_start, test_proc, proc_size_pg * PGSIZE);*/ - img_start = test_proc; + memcpy(img_start, test_proc, proc_size_pg * PGSIZE); /* instruction pointer at the beginning of the process image */ - proc[0].ctx.instr_ptr = (uint32_t)img_start; + proc[1].ctx.instr_ptr = (uint32_t)img_start; /* allocate the first page of the process stack */ stack_pg = ADDR_TO_PAGE(KMEM_START) - 1; if(pgalloc_vrange(stack_pg, 1) == -1) { panic("failed to allocate user stack page\n"); } - proc[0].ctx.stack_ptr = PAGE_TO_ADDR(stack_pg) + PGSIZE; + proc[1].ctx.stack_ptr = PAGE_TO_ADDR(stack_pg) + PGSIZE; /* create the virtual address space for this process */ - proc[0].ctx.pgtbl_paddr = clone_vm(); + proc[1].ctx.pgtbl_paddr = clone_vm(); /* we don't need the image and the stack in this address space */ - /*unmap_page_range(img_start_pg, proc_size_pg); - pgfree(img_start_pg, proc_size_pg);*/ + unmap_page_range(img_start_pg, proc_size_pg); + pgfree(img_start_pg, proc_size_pg); unmap_page(stack_pg); pgfree(stack_pg, 1); + /* add it to the scheduler queues */ + //add_proc(1, STATE_RUNNING); - /* switch to it by calling a function that takes the context - * of the current process, plugs the values into the interrupt - * stack, and calls iret. - * (should also set ss0/sp0 in TSS before returning) - */ - context_switch(0); - /* XXX this will never return */ + /* switch to the initial process, this never returns */ + context_switch(1); } @@ -76,7 +78,7 @@ ifrm.inum = ifrm.err = 0; ifrm.regs = ctx->regs; - ifrm.eflags = ctx->flags; + ifrm.eflags = ctx->flags | (1 << 9); ifrm.eip = ctx->instr_ptr; ifrm.cs = selector(SEGM_KCODE, 0); /* XXX change this when we setup the TSS */ @@ -89,3 +91,18 @@ intr_ret(ifrm); } + +int get_current_pid(void) +{ + return cur_pid; +} + +struct process *get_current_proc(void) +{ + return cur_pid ? &proc[cur_pid] : 0; +} + +struct process *get_process(int pid) +{ + return &proc[pid]; +} diff -r 1d8877d12de0 -r b1e8c8251884 src/proc.h --- a/src/proc.h Sat Jul 30 07:35:53 2011 +0300 +++ b/src/proc.h Mon Aug 01 06:45:29 2011 +0300 @@ -15,14 +15,29 @@ /* TODO add FPU state */ }; +enum proc_state { + STATE_RUNNING, + STATE_BLOCKED, + STATE_ZOMBIE +}; + struct process { - int parent; + int id, parent; + enum proc_state state; + + int ticks_left; struct context ctx; + + struct process *next, *prev; /* for the scheduler queues */ }; void init_proc(void); void context_switch(int pid); +int get_current_pid(void); +struct process *get_current_proc(void); +struct process *get_process(int pid); + #endif /* PROC_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/sched.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sched.c Mon Aug 01 06:45:29 2011 +0300 @@ -0,0 +1,154 @@ +#include +#include "sched.h" +#include "proc.h" +#include "intr.h" +#include "asmops.h" +#include "config.h" + +#define EMPTY(q) ((q).head == 0) + +struct proc_list { + struct process *head, *tail; +}; + +static void ins_back(struct proc_list *q, struct process *proc); +static void ins_front(struct proc_list *q, struct process *proc); +static void remove(struct proc_list *q, struct process *proc); + +static struct proc_list runq; +static struct proc_list waitq; +static struct proc_list zombieq; + +void schedule(void) +{ + if(EMPTY(runq)) { + /* idle "process". + * make sure interrupts are enabled before halting + */ + enable_intr(); + halt_cpu(); + /* 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. + */ + if(runq.head->ticks_left <= 0) { + if(runq.head->next) { + struct process *proc = runq.head; + remove(&runq, proc); + ins_back(&runq, proc); + } + + /* start a new timeslice */ + runq.head->ticks_left = TIMESLICE_TICKS; + } + + /* no need to re-enable interrupts, they will be enabled with the iret */ + context_switch(runq.head->id); +} + +int add_proc(int pid, enum proc_state state) +{ + int istate; + struct proc_list *q; + struct process *proc = get_process(pid); + + istate = get_intr_state(); + disable_intr(); + + q = state == STATE_RUNNING ? &runq : &waitq; + + ins_back(q, proc); + proc->state = state; + + set_intr_state(istate); + return 0; +} + +int block_proc(int pid) +{ + int istate; + struct process *proc = get_process(pid); + + if(proc->state != STATE_RUNNING) { + printf("block_proc: process %d not running\n", pid); + return -1; + } + + istate = get_intr_state(); + disable_intr(); + + remove(&runq, proc); + ins_back(&waitq, proc); + proc->state = STATE_BLOCKED; + + set_intr_state(istate); + return 0; +} + +int unblock_proc(int pid) +{ + int istate; + struct process *proc = get_process(pid); + + if(proc->state != STATE_BLOCKED) { + printf("unblock_proc: process %d not blocked\n", pid); + return -1; + } + + istate = get_intr_state(); + disable_intr(); + + remove(&waitq, proc); + ins_back(&runq, proc); + proc->state = STATE_RUNNING; + + set_intr_state(istate); + return 0; +} + + +static void ins_back(struct proc_list *q, struct process *proc) +{ + if(EMPTY(*q)) { + q->head = proc; + } else { + q->tail->next = proc; + } + + proc->next = 0; + proc->prev = q->tail; + q->tail = proc; +} + +static void ins_front(struct proc_list *q, struct process *proc) +{ + if(EMPTY(*q)) { + q->tail = proc; + } else { + q->head->prev = proc; + } + + proc->next = q->head; + proc->prev = 0; + q->head = proc; +} + +static void remove(struct proc_list *q, struct process *proc) +{ + if(proc->prev) { + proc->prev->next = proc->next; + } + if(proc->next) { + proc->next->prev = proc->prev; + } + if(q->head == proc) { + q->head = proc->next; + } + if(q->tail == proc) { + q->tail = proc->prev; + } +} diff -r 1d8877d12de0 -r b1e8c8251884 src/sched.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/sched.h Mon Aug 01 06:45:29 2011 +0300 @@ -0,0 +1,12 @@ +#ifndef SCHED_H_ +#define SCHED_H_ + +#include "proc.h" + +void schedule(void); + +int add_proc(int pid, enum proc_state state); +int block_proc(int pid); +int unblock_proc(int pid); + +#endif /* SCHED_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/syscall.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/syscall.c Mon Aug 01 06:45:29 2011 +0300 @@ -0,0 +1,56 @@ +#include +#include "syscall.h" +#include "intr.h" +#include "proc.h" +#include "sched.h" +#include "timer.h" + +static int (*sys_func[NUM_SYSCALLS])(); + +static void syscall(int inum, struct intr_frame *frm); + +static int sys_exit(int status); +static int sys_hello(void); +static int sys_sleep(int sec); + +void init_syscall(void) +{ + sys_func[SYS_EXIT] = sys_exit; + sys_func[SYS_HELLO] = sys_hello; + sys_func[SYS_SLEEP] = sys_sleep; + + interrupt(SYSCALL_INT, syscall); +} + +static void syscall(int inum, struct intr_frame *frm) +{ + int idx = frm->regs.eax; + + if(idx < 0 || idx >= NUM_SYSCALLS) { + printf("invalid syscall: %d\n", idx); + return; + } + + frm->regs.eax = sys_func[idx](frm->regs.ebx, frm->regs.ecx, frm->regs.edx, frm->regs.esi, frm->regs.edi); + schedule(); +} + +static int sys_exit(int status) +{ + return -1; /* not implemented yet */ +} + +static int sys_hello(void) +{ + /*printf("process %d says hello!\n", get_current_pid());*/ + return 0; +} + +static int sys_sleep(int sec) +{ + int pid = get_current_pid(); + /*printf("process %d will sleep for %d sec\n", pid, sec);*/ + start_timer(sec * 1000, (timer_func_t)unblock_proc, (void*)pid); + block_proc(pid); + return 0; +} diff -r 1d8877d12de0 -r b1e8c8251884 src/syscall.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/syscall.h Mon Aug 01 06:45:29 2011 +0300 @@ -0,0 +1,17 @@ +#ifndef SYSCALL_H_ +#define SYSCALL_H_ + +#define SYSCALL_INT 0x80 + +/* when we get rid of test_proc.S we'll turn this into an enum */ +#define SYS_EXIT 0 +#define SYS_HELLO 1 +#define SYS_SLEEP 2 + +#define NUM_SYSCALLS 3 + +#ifndef ASM +void init_syscall(void); +#endif + +#endif /* SYSCALL_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/sysnum.h --- a/src/sysnum.h Sat Jul 30 07:35:53 2011 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,10 +0,0 @@ -#ifndef SYSNUM_H_ -#define SYSNUM_H_ - -#define SYSCALL_INT 0x80 - -#define SYS_EXIT 0 -#define SYS_HELLO 1 -#define SYS_SLEEP 2 - -#endif /* SYSNUM_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/test_proc.S --- a/src/test_proc.S Sat Jul 30 07:35:53 2011 +0300 +++ b/src/test_proc.S Mon Aug 01 06:45:29 2011 +0300 @@ -1,4 +1,5 @@ -#include +#define ASM +#include .text .globl test_proc diff -r 1d8877d12de0 -r b1e8c8251884 src/timer.c --- a/src/timer.c Sat Jul 30 07:35:53 2011 +0300 +++ b/src/timer.c Mon Aug 01 06:45:29 2011 +0300 @@ -3,6 +3,8 @@ #include "intr.h" #include "asmops.h" #include "timer.h" +#include "proc.h" +#include "sched.h" #include "config.h" /* frequency of the oscillator driving the 8254 timer */ @@ -39,9 +41,24 @@ #define CMD_MODE_BCD 1 +#define MSEC_TO_TICKS(ms) ((ms) * TICK_FREQ_HZ / 1000) + +struct timer_event { + int dt; /* remaining ticks delta from the previous event */ + + void (*callback)(void*); + void *cbarg; + + struct timer_event *next; +}; + + static void intr_handler(); +static struct timer_event *evlist; + + void init_timer(void) { /* calculate the reload count: round(osc / freq) */ @@ -62,11 +79,101 @@ interrupt(IRQ_TO_INTR(0), intr_handler); } +int start_timer(unsigned long msec, timer_func_t cbfunc, void *cbarg) +{ + int ticks, tsum, istate; + struct timer_event *ev, *node; + + printf("start_timer(%lu)\n", msec); + + if((ticks = MSEC_TO_TICKS(msec)) <= 0) { + cbfunc(cbarg); + return 0; + } + + if(!(ev = malloc(sizeof *ev))) { + printf("start_timer: failed to allocate timer_event structure\n"); + return -1; + } + ev->callback = cbfunc; + ev->cbarg = cbarg; + + istate = get_intr_state(); + disable_intr(); + + /* insert at the beginning */ + if(!evlist || ticks <= evlist->dt) { + ev->next = evlist; + evlist = ev; + + ev->dt = ticks; + if(ev->next) { + ev->next->dt -= ticks; + } + set_intr_state(istate); + return 0; + } + + tsum = evlist->dt; + node = evlist; + + while(node->next && ticks > tsum + node->next->dt) { + tsum += node->next->dt; + node = node->next; + } + + ev->next = node->next; + node->next = ev; + + /* fix the relative times */ + ev->dt = ticks - tsum; + if(ev->next) { + ev->next->dt -= ev->dt; + } + + set_intr_state(istate); + return 0; +} + /* This will be called by the interrupt dispatcher approximately * every 1/250th of a second, so it must be extremely fast. * For now, just increasing a tick counter will suffice. */ -static void intr_handler() +static void intr_handler(int inum) { + int istate; + struct process *cur_proc; + nticks++; + + printf("TICKS: %d\n", nticks); + + istate = get_intr_state(); + disable_intr(); + + /* find out if there are any timers that have to go off */ + if(evlist) { + evlist->dt--; + + while(evlist->dt <= 0) { + struct timer_event *ev = evlist; + evlist = evlist->next; + + printf("timer going off!!!\n"); + ev->callback(ev->cbarg); + free(ev); + } + } + + if((cur_proc = get_current_proc())) { + if(--cur_proc->ticks_left <= 0) { + /* since schedule will not return, we have to notify + * the PIC that we're done with the IRQ handling + */ + end_of_irq(INTR_TO_IRQ(inum)); + schedule(); + } + } + + set_intr_state(istate); } diff -r 1d8877d12de0 -r b1e8c8251884 src/timer.h --- a/src/timer.h Sat Jul 30 07:35:53 2011 +0300 +++ b/src/timer.h Mon Aug 01 06:45:29 2011 +0300 @@ -1,8 +1,12 @@ #ifndef _TIMER_H_ #define _TIMER_H_ +typedef void (*timer_func_t)(void*); + unsigned long nticks; void init_timer(void); +int start_timer(unsigned long msec, timer_func_t cbfunc, void *cbarg); + #endif /* _TIMER_H_ */ diff -r 1d8877d12de0 -r b1e8c8251884 src/vm.c --- a/src/vm.c Sat Jul 30 07:35:53 2011 +0300 +++ b/src/vm.c Mon Aug 01 06:45:29 2011 +0300 @@ -37,7 +37,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, uint32_t err); +static void pgfault(int inum, struct intr_frame *frm); static struct page_range *alloc_node(void); static void free_node(struct page_range *node); @@ -457,18 +457,18 @@ } } -static void pgfault(int inum, uint32_t err) +static void pgfault(int inum, struct intr_frame *frm) { printf("~~~~ PAGE FAULT ~~~~\n"); printf("fault address: %x\n", get_fault_addr()); - if(err & PG_PRESENT) { - if(err & 8) { + if(frm->err & PG_PRESENT) { + if(frm->err & 8) { printf("reserved bit set in some paging structure\n"); } else { - printf("%s protection violation ", (err & PG_WRITABLE) ? "write" : "read"); - printf("in %s mode\n", err & PG_USER ? "user" : "kernel"); + printf("%s protection violation ", (frm->err & PG_WRITABLE) ? "write" : "read"); + printf("in %s mode\n", frm->err & PG_USER ? "user" : "kernel"); } } else { printf("page not present\n");