kern

changeset 55:88a6c4e192f9

Fixed most important task switching bugs. Now it seems that I can switch in and out of user space reliably.
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 15 Aug 2011 04:03:39 +0300
parents 4eaecb14fe31
children 0be4615594df
files src/intr-asm.S src/intr.c src/proc.c src/proc.h src/sched.c src/sched.h src/segm-asm.S src/segm.c src/timer.c src/vm-asm.S src/vm.c src/vm.h
diffstat 12 files changed, 262 insertions(+), 147 deletions(-) [+]
line diff
     1.1 --- a/src/intr-asm.S	Sun Aug 14 16:57:23 2011 +0300
     1.2 +++ b/src/intr-asm.S	Mon Aug 15 04:03:39 2011 +0300
     1.3 @@ -81,10 +81,11 @@
     1.4  	/* if we entered from userspace ss and cs is set correctly, but
     1.5       * we must make sure all the other selectors are set to the
     1.6       * kernel data segment */
     1.7 -	mov $SEGM_KDATA, %ds
     1.8 -	mov $SEGM_KDATA, %es
     1.9 -	mov $SEGM_KDATA, %fs
    1.10 -	mov $SEGM_KDATA, %gs
    1.11 +	mov %ss, %eax
    1.12 +	mov %eax, %ds
    1.13 +	mov %eax, %es
    1.14 +	mov %eax, %fs
    1.15 +	mov %eax, %gs
    1.16  	call dispatch_intr
    1.17  intr_ret_local:
    1.18  	/* restore general purpose registers */
     2.1 --- a/src/intr.c	Sun Aug 14 16:57:23 2011 +0300
     2.2 +++ b/src/intr.c	Mon Aug 15 04:03:39 2011 +0300
     2.3 @@ -4,6 +4,7 @@
     2.4  #include "segm.h"
     2.5  #include "asmops.h"
     2.6  #include "panic.h"
     2.7 +#include "syscall.h"
     2.8  
     2.9  /* IDT gate descriptor bits */
    2.10  #define GATE_TASK		(5 << 8)
    2.11 @@ -49,6 +50,7 @@
    2.12  static intr_func_t intr_func[256];
    2.13  
    2.14  static struct intr_frame *cur_intr_frame;
    2.15 +static int eoi_pending;
    2.16  
    2.17  
    2.18  void init_intr(void)
    2.19 @@ -74,6 +76,7 @@
    2.20  	 * setting up the maping of IRQs [0, 15] to interrupts [32, 47]
    2.21  	 */
    2.22  	init_pic(IRQ_OFFSET);
    2.23 +	eoi_pending = 0;
    2.24  }
    2.25  
    2.26  /* retrieve the current interrupt frame.
    2.27 @@ -98,6 +101,10 @@
    2.28  {
    2.29  	cur_intr_frame = &frm;
    2.30  
    2.31 +	if(IS_IRQ(frm.inum)) {
    2.32 +		eoi_pending = frm.inum;
    2.33 +	}
    2.34 +
    2.35  	if(intr_func[frm.inum]) {
    2.36  		intr_func[frm.inum](frm.inum);
    2.37  	} else {
    2.38 @@ -107,8 +114,9 @@
    2.39  		printf("unhandled interrupt %d\n", frm.inum);
    2.40  	}
    2.41  
    2.42 -	if(IS_IRQ(frm.inum)) {
    2.43 -		end_of_irq(INTR_TO_IRQ(frm.inum));
    2.44 +	disable_intr();
    2.45 +	if(eoi_pending) {
    2.46 +		end_of_irq(INTR_TO_IRQ(eoi_pending));
    2.47  	}
    2.48  }
    2.49  
    2.50 @@ -149,13 +157,31 @@
    2.51  static void set_intr_entry(int num, void (*handler)(void))
    2.52  {
    2.53  	int type = IS_TRAP(num) ? GATE_TRAP : GATE_INTR;
    2.54 -	gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, 0, type);
    2.55 +
    2.56 +	/* the syscall interrupt has to have a dpl of 3 otherwise calling it from
    2.57 +	 * user space will raise a general protection exception. All the rest should
    2.58 +	 * have a dpl of 0 to disallow user programs to execute critical interrupt
    2.59 +	 * handlers and possibly crashing the system.
    2.60 +	 */
    2.61 +	int dpl = (num == SYSCALL_INT) ? 3 : 0;
    2.62 +
    2.63 +	gate_desc(idt + num, selector(SEGM_KCODE, 0), (uint32_t)handler, dpl, type);
    2.64  }
    2.65  
    2.66  void end_of_irq(int irq)
    2.67  {
    2.68 +	int intr_state = get_intr_state();
    2.69 +	disable_intr();
    2.70 +
    2.71 +	if(!eoi_pending) {
    2.72 +		return;
    2.73 +	}
    2.74 +	eoi_pending = 0;
    2.75 +
    2.76  	if(irq > 7) {
    2.77  		outb(OCW2_EOI, PIC2_CMD);
    2.78  	}
    2.79  	outb(OCW2_EOI, PIC1_CMD);
    2.80 +
    2.81 +	set_intr_state(intr_state);
    2.82  }
     3.1 --- a/src/proc.c	Sun Aug 14 16:57:23 2011 +0300
     3.2 +++ b/src/proc.c	Mon Aug 15 04:03:39 2011 +0300
     3.3 @@ -1,6 +1,7 @@
     3.4  #include <stdio.h>
     3.5  #include <string.h>
     3.6  #include <assert.h>
     3.7 +#include "config.h"
     3.8  #include "proc.h"
     3.9  #include "tss.h"
    3.10  #include "vm.h"
    3.11 @@ -11,10 +12,12 @@
    3.12  #include "sched.h"
    3.13  #include "tss.h"
    3.14  
    3.15 -#define	FLAGS_INTR_BIT	9
    3.16 +#define	FLAGS_INTR_BIT	(1 << 9)
    3.17  
    3.18  static void start_first_proc(void);
    3.19  
    3.20 +/* defined in proc-asm.S */
    3.21 +uint32_t switch_stack(uint32_t new_stack);
    3.22  
    3.23  /* defined in test_proc.S */
    3.24  void test_proc(void);
    3.25 @@ -36,7 +39,7 @@
    3.26  	if((tss_page = pgalloc(1, MEM_KERNEL)) == -1) {
    3.27  		panic("failed to allocate memory for the task state segment\n");
    3.28  	}
    3.29 -	tss = (struct tss*)PAGE_TO_ADDR(tss_page);
    3.30 +	tss = (struct task_state*)PAGE_TO_ADDR(tss_page);
    3.31  
    3.32  	/* the kernel stack segment never changes so we might as well set it now
    3.33  	 * the only other thing that we use in the tss is the kernel stack pointer
    3.34 @@ -45,7 +48,7 @@
    3.35  	memset(tss, 0, sizeof *tss);
    3.36  	tss->ss0 = selector(SEGM_KDATA, 0);
    3.37  
    3.38 -	set_tss((uint32_t)virt_to_phys(tss));
    3.39 +	set_tss((uint32_t)tss);
    3.40  
    3.41  	/* initialize system call handler (see syscall.c) */
    3.42  	init_syscall();
    3.43 @@ -58,7 +61,7 @@
    3.44  {
    3.45  	struct process *p;
    3.46  	int proc_size_pg, img_start_pg, stack_pg;
    3.47 -	uint32_t img_start_addr, ustack_addr;
    3.48 +	uint32_t img_start_addr;
    3.49  	struct intr_frame ifrm;
    3.50  
    3.51  	/* prepare the first process */
    3.52 @@ -66,6 +69,12 @@
    3.53  	p->id = 1;
    3.54  	p->parent = 0;	/* no parent for init */
    3.55  
    3.56 +	p->ticks_left = TIMESLICE_TICKS;
    3.57 +	p->next = p->prev = 0;
    3.58 +
    3.59 +	/* the first process may keep this existing page table */
    3.60 +	p->ctx.pgtbl_paddr = get_pgdir_addr();
    3.61 +
    3.62  	/* allocate a chunk of memory for the process image
    3.63  	 * and copy the code of test_proc there.
    3.64  	 */
    3.65 @@ -102,7 +111,7 @@
    3.66  	ifrm.esp = PAGE_TO_ADDR(stack_pg) + PGSIZE;
    3.67  	ifrm.ss = selector(SEGM_UDATA, 3);
    3.68  	/* instruction pointer at the beginning of the process image */
    3.69 -	ifrm.regs.eip = img_start_addr;
    3.70 +	ifrm.eip = img_start_addr;
    3.71  	ifrm.cs = selector(SEGM_UCODE, 3);
    3.72  	/* make sure the user will run with interrupts enabled */
    3.73  	ifrm.eflags = FLAGS_INTR_BIT;
    3.74 @@ -110,7 +119,9 @@
    3.75  	ifrm.ds = ifrm.es = ifrm.fs = ifrm.gs = ifrm.ss;
    3.76  
    3.77  	/* add it to the scheduler queues */
    3.78 -	add_proc(p->id, STATE_RUNNABLE);
    3.79 +	add_proc(p->id);
    3.80 +
    3.81 +	cur_pid = p->id; /* make it current */
    3.82  
    3.83  	/* execute a fake return from interrupt with the fake stack frame */
    3.84  	intr_ret(ifrm);
    3.85 @@ -121,6 +132,8 @@
    3.86  {
    3.87  	struct process *prev, *new;
    3.88  
    3.89 +	assert(get_intr_state() == 0);
    3.90 +
    3.91  	if(cur_pid == pid) {
    3.92  		return;	/* nothing to be done */
    3.93  	}
    3.94 @@ -141,7 +154,7 @@
    3.95  	/* make sure we'll return to the correct kernel stack next time
    3.96  	 * we enter from userspace
    3.97  	 */
    3.98 -	tss->esp0 = PAGE_TO_ADDR(p->kern_stack_pg) + KERN_STACK_SIZE;
    3.99 +	tss->esp0 = PAGE_TO_ADDR(new->kern_stack_pg) + KERN_STACK_SIZE;
   3.100  }
   3.101  
   3.102  int get_current_pid(void)
     4.1 --- a/src/proc.h	Sun Aug 14 16:57:23 2011 +0300
     4.2 +++ b/src/proc.h	Mon Aug 15 04:03:39 2011 +0300
     4.3 @@ -26,6 +26,9 @@
     4.4  	int id, parent;
     4.5  	enum proc_state state;
     4.6  
     4.7 +	/* when blocked it's waiting for a wakeup on this address */
     4.8 +	void *wait_addr;
     4.9 +
    4.10  	int ticks_left;
    4.11  
    4.12  	/* extends of the process heap, increased by sbrk */
     5.1 --- a/src/sched.c	Sun Aug 14 16:57:23 2011 +0300
     5.2 +++ b/src/sched.c	Mon Aug 15 04:03:39 2011 +0300
     5.3 @@ -1,35 +1,36 @@
     5.4  #include <stdio.h>
     5.5 +#include <assert.h>
     5.6  #include "sched.h"
     5.7  #include "proc.h"
     5.8  #include "intr.h"
     5.9  #include "asmops.h"
    5.10  #include "config.h"
    5.11  
    5.12 -#define EMPTY(q)	((q).head == 0)
    5.13 +#define EMPTY(q)	((q)->head == 0)
    5.14  
    5.15  struct proc_list {
    5.16  	struct process *head, *tail;
    5.17  };
    5.18  
    5.19 -static void ins_back(struct proc_list *q, struct process *proc);
    5.20 -static void ins_front(struct proc_list *q, struct process *proc);
    5.21 -static void remove(struct proc_list *q, struct process *proc);
    5.22 +static void idle_proc(void);
    5.23 +static void ins_back(struct proc_list *list, struct process *proc);
    5.24 +static void ins_front(struct proc_list *list, struct process *proc);
    5.25 +static void remove(struct proc_list *list, struct process *proc);
    5.26 +static int hash_addr(void *addr);
    5.27  
    5.28  static struct proc_list runq;
    5.29 -static struct proc_list waitq;
    5.30  static struct proc_list zombieq;
    5.31  
    5.32 +#define HTBL_SIZE	101
    5.33 +static struct proc_list wait_htable[HTBL_SIZE];
    5.34 +
    5.35 +
    5.36  void schedule(void)
    5.37  {
    5.38  	disable_intr();
    5.39  
    5.40 -	if(EMPTY(runq)) {
    5.41 -		/* idle "process".
    5.42 -		 * make sure interrupts are enabled before halting
    5.43 -		 */
    5.44 -		enable_intr();
    5.45 -		halt_cpu();
    5.46 -		printf("fuck you!\n");
    5.47 +	if(EMPTY(&runq)) {
    5.48 +		idle_proc();
    5.49  		/* this won't return, it'll just wake up in an interrupt later */
    5.50  	}
    5.51  
    5.52 @@ -47,14 +48,13 @@
    5.53  		runq.head->ticks_left = TIMESLICE_TICKS;
    5.54  	}
    5.55  
    5.56 -	/* no need to re-enable interrupts, they will be enabled with the iret */
    5.57 +	/* always enter context_switch with interrupts disabled */
    5.58  	context_switch(runq.head->id);
    5.59  }
    5.60  
    5.61 -int add_proc(int pid, enum proc_state state)
    5.62 +void add_proc(int pid)
    5.63  {
    5.64  	int istate;
    5.65 -	struct proc_list *q;
    5.66  	struct process *proc;
    5.67  
    5.68  	istate = get_intr_state();
    5.69 @@ -62,85 +62,102 @@
    5.70  
    5.71  	proc = get_process(pid);
    5.72  
    5.73 -	q = state == STATE_RUNNABLE ? &runq : &waitq;
    5.74 -
    5.75 -	ins_back(q, proc);
    5.76 -	proc->state = state;
    5.77 -
    5.78 -	set_intr_state(istate);
    5.79 -	return 0;
    5.80 -}
    5.81 -
    5.82 -int block_proc(int pid)
    5.83 -{
    5.84 -	int istate;
    5.85 -	struct process *proc = get_process(pid);
    5.86 -
    5.87 -	if(proc->state != STATE_RUNNABLE) {
    5.88 -		printf("block_proc: process %d not running\n", pid);
    5.89 -		return -1;
    5.90 -	}
    5.91 -
    5.92 -	istate = get_intr_state();
    5.93 -	disable_intr();
    5.94 -
    5.95 -	remove(&runq, proc);
    5.96 -	ins_back(&waitq, proc);
    5.97 -	proc->state = STATE_BLOCKED;
    5.98 -
    5.99 -	set_intr_state(istate);
   5.100 -	return 0;
   5.101 -}
   5.102 -
   5.103 -int unblock_proc(int pid)
   5.104 -{
   5.105 -	int istate;
   5.106 -	struct process *proc = get_process(pid);
   5.107 -
   5.108 -	if(proc->state != STATE_BLOCKED) {
   5.109 -		printf("unblock_proc: process %d not blocked\n", pid);
   5.110 -		return -1;
   5.111 -	}
   5.112 -
   5.113 -	istate = get_intr_state();
   5.114 -	disable_intr();
   5.115 -
   5.116 -	remove(&waitq, proc);
   5.117  	ins_back(&runq, proc);
   5.118  	proc->state = STATE_RUNNABLE;
   5.119  
   5.120  	set_intr_state(istate);
   5.121 -	return 0;
   5.122  }
   5.123  
   5.124 +/* block the process until we get a wakeup call for address ev */
   5.125 +void wait(void *wait_addr)
   5.126 +{
   5.127 +	struct process *p;
   5.128 +	int hash_idx;
   5.129  
   5.130 -static void ins_back(struct proc_list *q, struct process *proc)
   5.131 +	disable_intr();
   5.132 +
   5.133 +	p = get_current_proc();
   5.134 +	assert(p);
   5.135 +
   5.136 +	/* remove it from the runqueue ... */
   5.137 +	remove(&runq, p);
   5.138 +
   5.139 +	/* and place it in the wait hash table based on sleep_addr */
   5.140 +	hash_idx = hash_addr(wait_addr);
   5.141 +	ins_back(wait_htable + hash_idx, p);
   5.142 +
   5.143 +	p->state = STATE_BLOCKED;
   5.144 +	p->wait_addr = wait_addr;
   5.145 +}
   5.146 +
   5.147 +/* wake up all the processes sleeping on this address */
   5.148 +void wakeup(void *wait_addr)
   5.149  {
   5.150 -	if(EMPTY(*q)) {
   5.151 -		q->head = proc;
   5.152 +	int hash_idx;
   5.153 +	struct process *iter;
   5.154 +	struct proc_list *list;
   5.155 +
   5.156 +	hash_idx = hash_addr(wait_addr);
   5.157 +	list = wait_htable + hash_idx;
   5.158 +
   5.159 +	iter = list->head;
   5.160 +	while(iter) {
   5.161 +		if(iter->wait_addr == wait_addr) {
   5.162 +			/* found one, remove it, and make it runnable */
   5.163 +			struct process *p = iter;
   5.164 +			iter = iter->next;
   5.165 +
   5.166 +			remove(list, p);
   5.167 +			p->state = STATE_RUNNABLE;
   5.168 +			ins_back(&runq, p);
   5.169 +		} else {
   5.170 +			iter = iter->next;
   5.171 +		}
   5.172 +	}
   5.173 +}
   5.174 +
   5.175 +static void idle_proc(void)
   5.176 +{
   5.177 +	/* make sure we send any pending EOIs if needed.
   5.178 +	 * end_of_irq will actually check if it's needed first.
   5.179 +	 */
   5.180 +	struct intr_frame *ifrm = get_intr_frame();
   5.181 +	end_of_irq(INTR_TO_IRQ(ifrm->inum));
   5.182 +
   5.183 +	/* make sure interrupts are enabled before halting */
   5.184 +	enable_intr();
   5.185 +	halt_cpu();
   5.186 +}
   5.187 +
   5.188 +
   5.189 +/* list operations */
   5.190 +static void ins_back(struct proc_list *list, struct process *proc)
   5.191 +{
   5.192 +	if(EMPTY(list)) {
   5.193 +		list->head = proc;
   5.194  	} else {
   5.195 -		q->tail->next = proc;
   5.196 +		list->tail->next = proc;
   5.197  	}
   5.198  
   5.199  	proc->next = 0;
   5.200 -	proc->prev = q->tail;
   5.201 -	q->tail = proc;
   5.202 +	proc->prev = list->tail;
   5.203 +	list->tail = proc;
   5.204  }
   5.205  
   5.206 -static void ins_front(struct proc_list *q, struct process *proc)
   5.207 +static void ins_front(struct proc_list *list, struct process *proc)
   5.208  {
   5.209 -	if(EMPTY(*q)) {
   5.210 -		q->tail = proc;
   5.211 +	if(EMPTY(list)) {
   5.212 +		list->tail = proc;
   5.213  	} else {
   5.214 -		q->head->prev = proc;
   5.215 +		list->head->prev = proc;
   5.216  	}
   5.217  
   5.218 -	proc->next = q->head;
   5.219 +	proc->next = list->head;
   5.220  	proc->prev = 0;
   5.221 -	q->head = proc;
   5.222 +	list->head = proc;
   5.223  }
   5.224  
   5.225 -static void remove(struct proc_list *q, struct process *proc)
   5.226 +static void remove(struct proc_list *list, struct process *proc)
   5.227  {
   5.228  	if(proc->prev) {
   5.229  		proc->prev->next = proc->next;
   5.230 @@ -148,10 +165,15 @@
   5.231  	if(proc->next) {
   5.232  		proc->next->prev = proc->prev;
   5.233  	}
   5.234 -	if(q->head == proc) {
   5.235 -		q->head = proc->next;
   5.236 +	if(list->head == proc) {
   5.237 +		list->head = proc->next;
   5.238  	}
   5.239 -	if(q->tail == proc) {
   5.240 -		q->tail = proc->prev;
   5.241 +	if(list->tail == proc) {
   5.242 +		list->tail = proc->prev;
   5.243  	}
   5.244  }
   5.245 +
   5.246 +static int hash_addr(void *addr)
   5.247 +{
   5.248 +	return (uint32_t)addr % HTBL_SIZE;
   5.249 +}
     6.1 --- a/src/sched.h	Sun Aug 14 16:57:23 2011 +0300
     6.2 +++ b/src/sched.h	Mon Aug 15 04:03:39 2011 +0300
     6.3 @@ -5,8 +5,9 @@
     6.4  
     6.5  void schedule(void);
     6.6  
     6.7 -int add_proc(int pid, enum proc_state state);
     6.8 -int block_proc(int pid);
     6.9 -int unblock_proc(int pid);
    6.10 +void add_proc(int pid);
    6.11 +
    6.12 +void wait(void *wait_addr);
    6.13 +void wakeup(void *wait_addr);
    6.14  
    6.15  #endif	/* SCHED_H_ */
     7.1 --- a/src/segm-asm.S	Sun Aug 14 16:57:23 2011 +0300
     7.2 +++ b/src/segm-asm.S	Mon Aug 15 04:03:39 2011 +0300
     7.3 @@ -42,5 +42,6 @@
     7.4   * loads the TSS selector in the task register */
     7.5  	.globl set_task_reg
     7.6  set_task_reg:
     7.7 +	mov 4(%esp), %eax
     7.8  	ltr 4(%esp)
     7.9  	ret
     8.1 --- a/src/segm.c	Sun Aug 14 16:57:23 2011 +0300
     8.2 +++ b/src/segm.c	Mon Aug 15 04:03:39 2011 +0300
     8.3 @@ -1,6 +1,7 @@
     8.4  #include <string.h>
     8.5  #include "segm.h"
     8.6  #include "desc.h"
     8.7 +#include "tss.h"
     8.8  
     8.9  /* bits for the 3rd 16bt part of the descriptor */
    8.10  #define BIT_ACCESSED	(1 << 8)
    8.11 @@ -21,10 +22,11 @@
    8.12  
    8.13  enum {TYPE_DATA, TYPE_CODE};
    8.14  
    8.15 -#define TSS_TYPE_BITS	(BIT_ACCESSED | BIT_CODE)
    8.16 +/* we need the following bit pattern at the 8th bit excluding the busy bit: 1001 */
    8.17 +#define TSS_TYPE_BITS	(9 << 8)
    8.18  
    8.19  static void segm_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, int type);
    8.20 -static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, unsigned int busy);
    8.21 +static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl);
    8.22  
    8.23  /* these functions are implemented in segm-asm.S */
    8.24  void setup_selectors(uint16_t code, uint16_t data);
    8.25 @@ -57,7 +59,7 @@
    8.26  
    8.27  void set_tss(uint32_t addr)
    8.28  {
    8.29 -	task_desc(gdt + SEGM_TASK, 0, sizeof(struct tss) - 1, 3, TSS_BUSY);
    8.30 +	task_desc(gdt + SEGM_TASK, addr, sizeof(struct task_state) - 1, 3);
    8.31  	set_task_reg(selector(SEGM_TASK, 0));
    8.32  }
    8.33  
    8.34 @@ -79,12 +81,44 @@
    8.35  	desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN | BIT_BIG;
    8.36  }
    8.37  
    8.38 -static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl, unsigned int busy)
    8.39 +static void task_desc(desc_t *desc, uint32_t base, uint32_t limit, int dpl)
    8.40  {
    8.41  	desc->d[0] = limit & 0xffff;
    8.42  	desc->d[1] = base & 0xffff;
    8.43  
    8.44  	desc->d[2] = ((base >> 16) & 0xff) | ((dpl & 3) << 13) | BIT_PRESENT |
    8.45 -		TSS_TYPE_BITS | busy;
    8.46 +		TSS_TYPE_BITS; /* XXX busy ? */
    8.47  	desc->d[3] = ((limit >> 16) & 0xf) | ((base >> 16) & 0xff00) | BIT_GRAN;
    8.48  }
    8.49 +/*
    8.50 +static void dbg_print_gdt(void)
    8.51 +{
    8.52 +	int i;
    8.53 +
    8.54 +	printf("Global Descriptor Table\n");
    8.55 +	printf("-----------------------\n");
    8.56 +
    8.57 +	for(i=0; i<6; i++) {
    8.58 +		print_desc(gdt + i);
    8.59 +	}
    8.60 +}
    8.61 +
    8.62 +static void print_desc(desc_t *desc)
    8.63 +{
    8.64 +	uint32_t base, limit;
    8.65 +	int dpl, g, db, l, avl, p, s, type;
    8.66 +	char *type_str;
    8.67 +
    8.68 +	base = (uint32_t)desc->d[1] | ((uint32_t)(desc->d[2] & 0xff) << 16) | ((uint32_t)(desc->d[3] >> 8) << 24);
    8.69 +	limit = (uint32_t)desc->d[0] | ((uint32_t)(desc->d[3] & 0xf) << 16);
    8.70 +	dpl = (desc->d[2] >> 13) & 3;
    8.71 +	type = (desc->d[2] >> 8) & 0xf;
    8.72 +	g = (desc->d[3] >> 23) & 1;
    8.73 +	db = (desc->d[3] >> 22) & 1;
    8.74 +	l = (desc->d[3] >> 21) & 1;
    8.75 +	avl = (desc->d[3] >> 20) & 1;
    8.76 +
    8.77 +	p = (desc->d[2] >> 15) & 1;
    8.78 +	s = (desc->d[2] >> 12) & 1;
    8.79 +}
    8.80 +*/
     9.1 --- a/src/timer.c	Sun Aug 14 16:57:23 2011 +0300
     9.2 +++ b/src/timer.c	Mon Aug 15 04:03:39 2011 +0300
     9.3 @@ -45,10 +45,6 @@
     9.4  
     9.5  struct timer_event {
     9.6  	int dt;	/* remaining ticks delta from the previous event */
     9.7 -
     9.8 -	void (*callback)(void*);
     9.9 -	void *cbarg;
    9.10 -
    9.11  	struct timer_event *next;
    9.12  };
    9.13  
    9.14 @@ -79,24 +75,21 @@
    9.15  	interrupt(IRQ_TO_INTR(0), intr_handler);
    9.16  }
    9.17  
    9.18 -int start_timer(unsigned long msec, timer_func_t cbfunc, void *cbarg)
    9.19 +void sleep(unsigned long msec)
    9.20  {
    9.21  	int ticks, tsum, istate;
    9.22  	struct timer_event *ev, *node;
    9.23  
    9.24 -	printf("start_timer(%lu)\n", msec);
    9.25 +	printf("sleep(%lu)\n", msec);
    9.26  
    9.27  	if((ticks = MSEC_TO_TICKS(msec)) <= 0) {
    9.28 -		cbfunc(cbarg);
    9.29 -		return 0;
    9.30 +		return;
    9.31  	}
    9.32  
    9.33  	if(!(ev = malloc(sizeof *ev))) {
    9.34 -		printf("start_timer: failed to allocate timer_event structure\n");
    9.35 -		return -1;
    9.36 +		printf("sleep: failed to allocate timer_event structure\n");
    9.37 +		return;
    9.38  	}
    9.39 -	ev->callback = cbfunc;
    9.40 -	ev->cbarg = cbarg;
    9.41  
    9.42  	istate = get_intr_state();
    9.43  	disable_intr();
    9.44 @@ -110,29 +103,30 @@
    9.45  		if(ev->next) {
    9.46  			ev->next->dt -= ticks;
    9.47  		}
    9.48 -		set_intr_state(istate);
    9.49 -		return 0;
    9.50 -	}
    9.51 +	} else {
    9.52  
    9.53 -	tsum = evlist->dt;
    9.54 -	node = evlist;
    9.55 +		tsum = evlist->dt;
    9.56 +		node = evlist;
    9.57  
    9.58 -	while(node->next && ticks > tsum + node->next->dt) {
    9.59 -		tsum += node->next->dt;
    9.60 -		node = node->next;
    9.61 -	}
    9.62 +		while(node->next && ticks > tsum + node->next->dt) {
    9.63 +			tsum += node->next->dt;
    9.64 +			node = node->next;
    9.65 +		}
    9.66  
    9.67 -	ev->next = node->next;
    9.68 -	node->next = ev;
    9.69 +		ev->next = node->next;
    9.70 +		node->next = ev;
    9.71  
    9.72 -	/* fix the relative times */
    9.73 -	ev->dt = ticks - tsum;
    9.74 -	if(ev->next) {
    9.75 -		ev->next->dt -= ev->dt;
    9.76 +		/* fix the relative times */
    9.77 +		ev->dt = ticks - tsum;
    9.78 +		if(ev->next) {
    9.79 +			ev->next->dt -= ev->dt;
    9.80 +		}
    9.81  	}
    9.82  
    9.83  	set_intr_state(istate);
    9.84 -	return 0;
    9.85 +
    9.86 +	/* wait on the address of this timer event */
    9.87 +	wait(ev);
    9.88  }
    9.89  
    9.90  /* This will be called by the interrupt dispatcher approximately
    9.91 @@ -160,17 +154,15 @@
    9.92  			evlist = evlist->next;
    9.93  
    9.94  			printf("timer going off!!!\n");
    9.95 -			ev->callback(ev->cbarg);
    9.96 +			/* wake up all processes waiting on this address */
    9.97 +			wakeup(ev);
    9.98  			free(ev);
    9.99  		}
   9.100  	}
   9.101  
   9.102  	if((cur_proc = get_current_proc())) {
   9.103 +		/* if the timeslice of this process has expire, call the scheduler */
   9.104  		if(--cur_proc->ticks_left <= 0) {
   9.105 -			/* since schedule will not return, we have to notify
   9.106 -			 * the PIC that we're done with the IRQ handling
   9.107 -			 */
   9.108 -			end_of_irq(INTR_TO_IRQ(inum));
   9.109  			schedule();
   9.110  		}
   9.111  	}
    10.1 --- a/src/vm-asm.S	Sun Aug 14 16:57:23 2011 +0300
    10.2 +++ b/src/vm-asm.S	Mon Aug 15 04:03:39 2011 +0300
    10.3 @@ -34,6 +34,13 @@
    10.4  	movl %eax, %cr3
    10.5  	ret
    10.6  
    10.7 +/* get_pgdir_addr(void)
    10.8 + * returns the physical address of the page table directory (cr3) */
    10.9 +	.globl get_pgdir_addr
   10.10 +get_pgdir_addr:
   10.11 +	movl %cr3, %eax
   10.12 +	ret
   10.13 +
   10.14  /* flush_tlb(void)
   10.15   * invalidates the whole TLB. entries for pages marked as global
   10.16   * are unaffected */
    11.1 --- a/src/vm.c	Sun Aug 14 16:57:23 2011 +0300
    11.2 +++ b/src/vm.c	Mon Aug 15 04:03:39 2011 +0300
    11.3 @@ -129,8 +129,19 @@
    11.4  	pgidx = PAGE_TO_PGTBL_PG(vpage);
    11.5  
    11.6  	if(!(pgdir[diridx] & PG_PRESENT)) {
    11.7 +		/* no page table present, we must allocate one */
    11.8  		uint32_t addr = alloc_phys_page();
    11.9 -		pgdir[diridx] = addr | (attr & ATTR_PGDIR_MASK) | PG_PRESENT;
   11.10 +
   11.11 +		/* make sure all page directory entries in the below the kernel vm
   11.12 +		 * split have the user and writable bits set, otherwise further user
   11.13 +		 * mappings on the same 4mb block will be unusable in user space.
   11.14 +		 */
   11.15 +		unsigned int pgdir_attr = attr;
   11.16 +		if(vpage < ADDR_TO_PAGE(KMEM_START)) {
   11.17 +			pgdir_attr |= PG_USER | PG_WRITABLE;
   11.18 +		}
   11.19 +
   11.20 +		pgdir[diridx] = addr | (pgdir_attr & ATTR_PGDIR_MASK) | PG_PRESENT;
   11.21  
   11.22  		pgtbl = pgon ? PGTBL(diridx) : (uint32_t*)addr;
   11.23  		memset(pgtbl, 0, PGSIZE);
   11.24 @@ -265,7 +276,6 @@
   11.25  {
   11.26  	int intr_state, ret = -1;
   11.27  	struct page_range *node, *prev, dummy;
   11.28 -	unsigned int attr = 0;	/* TODO */
   11.29  
   11.30  	intr_state = get_intr_state();
   11.31  	disable_intr();
   11.32 @@ -296,6 +306,9 @@
   11.33  	}
   11.34  
   11.35  	if(ret >= 0) {
   11.36 +		/*unsigned int attr = (area == MEM_USER) ? (PG_USER | PG_WRITABLE) : PG_GLOBAL;*/
   11.37 +		unsigned int attr = (area == MEM_USER) ? (PG_USER | PG_WRITABLE) : 0;
   11.38 +
   11.39  		/* allocate physical storage and map */
   11.40  		if(map_page_range(ret, num, -1, attr) == -1) {
   11.41  			ret = -1;
   11.42 @@ -310,7 +323,6 @@
   11.43  {
   11.44  	struct page_range *node, *prev, dummy;
   11.45  	int area, intr_state, ret = -1;
   11.46 -	unsigned int attr = 0;	/* TODO */
   11.47  
   11.48  	area = (start >= ADDR_TO_PAGE(KMEM_START)) ? MEM_KERNEL : MEM_USER;
   11.49  	if(area == MEM_USER && start + num > ADDR_TO_PAGE(KMEM_START)) {
   11.50 @@ -376,6 +388,9 @@
   11.51  	}
   11.52  
   11.53  	if(ret >= 0) {
   11.54 +		/*unsigned int attr = (area == MEM_USER) ? (PG_USER | PG_WRITABLE) : PG_GLOBAL;*/
   11.55 +		unsigned int attr = (area == MEM_USER) ? (PG_USER | PG_WRITABLE) : 0;
   11.56 +
   11.57  		/* allocate physical storage and map */
   11.58  		if(map_page_range(ret, num, -1, attr) == -1) {
   11.59  			ret = -1;
   11.60 @@ -464,21 +479,20 @@
   11.61  	uint32_t fault_addr = get_fault_addr();
   11.62  
   11.63  	/* the fault occured in user space */
   11.64 -	if(frm->esp < KMEM_START + 1) {
   11.65 +	if(frm->err & PG_USER) {
   11.66  		int fault_page = ADDR_TO_PAGE(fault_addr);
   11.67  		struct process *proc = get_current_proc();
   11.68 +		printf("DBG: page fault in user space\n");
   11.69  		assert(proc);
   11.70  
   11.71 -		printf("DBG: page fault in user space\n");
   11.72 -
   11.73  		if(frm->err & PG_PRESENT) {
   11.74  			/* it's not due to a missing page, just panic */
   11.75  			goto unhandled;
   11.76  		}
   11.77  
   11.78  		/* detect if it's an automatic stack growth deal */
   11.79 -		if(fault_page < proc->stack_start_pg && proc->stack_start_pg - fault_page < USTACK_MAXGROW) {
   11.80 -			int num_pages = proc->stack_start_pg - fault_page;
   11.81 +		if(fault_page < proc->user_stack_pg && proc->user_stack_pg - fault_page < USTACK_MAXGROW) {
   11.82 +			int num_pages = proc->user_stack_pg - fault_page;
   11.83  			printf("growing user (%d) stack by %d pages\n", proc->id, num_pages);
   11.84  
   11.85  			if(pgalloc_vrange(fault_page, num_pages) != fault_page) {
   11.86 @@ -486,8 +500,7 @@
   11.87  				/* TODO: in the future we'd SIGSEGV the process here, for now just panic */
   11.88  				goto unhandled;
   11.89  			}
   11.90 -			proc->stack_start_pg = fault_page;
   11.91 -
   11.92 +			proc->user_stack_pg = fault_page;
   11.93  			return;
   11.94  		}
   11.95  	}
   11.96 @@ -500,8 +513,8 @@
   11.97  		if(frm->err & 8) {
   11.98  			printf("reserved bit set in some paging structure\n");
   11.99  		} else {
  11.100 -			printf("%s protection violation ", (frm->err & PG_WRITABLE) ? "write" : "read");
  11.101 -			printf("in %s mode\n", frm->err & PG_USER ? "user" : "kernel");
  11.102 +			printf("%s protection violation ", (frm->err & PG_WRITABLE) ? "WRITE" : "READ");
  11.103 +			printf("in %s mode\n", (frm->err & PG_USER) ? "user" : "kernel");
  11.104  		}
  11.105  	} else {
  11.106  		printf("page not present\n");
  11.107 @@ -553,7 +566,7 @@
  11.108  	/*printf("free_node\n");*/
  11.109  }
  11.110  
  11.111 -
  11.112 +#if 0
  11.113  /* clone_vm makes a copy of the current page tables, thus duplicating the
  11.114   * virtual address space.
  11.115   *
  11.116 @@ -594,7 +607,7 @@
  11.117  	for(i=0; i<kstart_dirent; i++) {
  11.118  		if(pgdir[i] & PG_PRESENT) {
  11.119  			paddr = alloc_phys_page();
  11.120 -			map_page(tblpg, ADDR_TO_PAGE(paddr), 0);
  11.121 +			map_page(tblpg, ADDR_TO_PAGE(paddr), PG_USER | PG_WRITABLE);
  11.122  
  11.123  			/* copy the page table */
  11.124  			memcpy(ntbl, PGTBL(i), PGSIZE);
  11.125 @@ -606,7 +619,7 @@
  11.126  		}
  11.127  	}
  11.128  
  11.129 -	/* kernel space */
  11.130 +	/* for the kernel space we'll just use the same page tables */
  11.131  	for(i=kstart_dirent; i<1024; i++) {
  11.132  		ndir[i] = pgdir[i];
  11.133  	}
  11.134 @@ -622,6 +635,7 @@
  11.135  
  11.136  	return paddr;
  11.137  }
  11.138 +#endif
  11.139  
  11.140  
  11.141  void dbg_print_vm(int area)
    12.1 --- a/src/vm.h	Sun Aug 14 16:57:23 2011 +0300
    12.2 +++ b/src/vm.h	Mon Aug 15 04:03:39 2011 +0300
    12.3 @@ -63,5 +63,6 @@
    12.4  
    12.5  /* defined in vm-asm.S */
    12.6  void set_pgdir_addr(uint32_t addr);
    12.7 +uint32_t get_pgdir_addr(void);
    12.8  
    12.9  #endif	/* VM_H_ */