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)