1 #include "types.h" 2 #include "mmu.h" 3 #include "x86.h" 4 #include "proc.h" 5 #include "param.h" 6 #include "defs.h" 7 8 struct proc proc[NPROC]; 9 struct proc *curproc; 10 int next_pid = 1; 11 12 /* 13 * set up a process's task state and segment descriptors 14 * correctly, given its current size and address in memory. 15 * this should be called whenever the latter change. 16 * doesn't change the cpu's current segmentation setup. 17 */ 18 void 19 setupsegs(struct proc *p) 20 { 21 memset(&p->ts, 0, sizeof(struct Taskstate)); 22 p->ts.ts_ss0 = SEG_KDATA << 3; 23 p->ts.ts_esp0 = (unsigned)(p->kstack + KSTACKSIZE); 24 25 // XXX it may be wrong to modify the current segment table! 26 27 p->gdt[0] = SEG_NULL; 28 p->gdt[SEG_KCODE] = SEG(STA_X|STA_R, 0, 0xffffffff, 0); 29 p->gdt[SEG_KDATA] = SEG(STA_W, 0, 0xffffffff, 0); 30 p->gdt[SEG_TSS] = SEG16(STS_T32A, (unsigned) &p->ts, 31 sizeof(p->ts), 0); 32 p->gdt[SEG_TSS].sd_s = 0; 33 p->gdt[SEG_UCODE] = SEG(STA_X|STA_R, (unsigned)p->mem, p->sz, 3); 34 p->gdt[SEG_UDATA] = SEG(STA_W, (unsigned)p->mem, p->sz, 3); 35 p->gdt_pd.pd__garbage = 0; 36 p->gdt_pd.pd_lim = sizeof(p->gdt) - 1; 37 p->gdt_pd.pd_base = (unsigned) p->gdt; 38 } 39 40 extern void trapret(); 41 42 /* 43 * internal fork(). does not copy kernel stack; instead, 44 * sets up the stack to return as if from system call. 45 */ 46 struct proc * 47 newproc() 48 { 49 struct proc *np; 50 unsigned *sp; 51 52 for(np = &proc[1]; np < &proc[NPROC]; np++) 53 if(np->state == UNUSED) 54 break; 55 if(np >= &proc[NPROC]) 56 return 0; 57 58 np->pid = next_pid++; 59 np->ppid = curproc->pid; 60 np->sz = curproc->sz; 61 np->mem = kalloc(curproc->sz); 62 if(np->mem == 0) 63 return 0; 64 memcpy(np->mem, curproc->mem, np->sz); 65 np->kstack = kalloc(KSTACKSIZE); 66 if(np->kstack == 0){ 67 kfree(np->mem, curproc->sz); 68 return 0; 69 } 70 setupsegs(np); 71 72 // set up kernel stack to return to user space 73 np->tf = (struct Trapframe *) (np->kstack + KSTACKSIZE - sizeof(struct Trapframe)); 74 *(np->tf) = *(curproc->tf); 75 sp = (unsigned *) np->tf; 76 *(--sp) = (unsigned) &trapret; // for return from swtch() 77 *(--sp) = 0; // previous bp for leave in swtch() 78 np->esp = (unsigned) sp; 79 np->ebp = (unsigned) sp; 80 81 np->state = RUNNABLE; 82 83 cprintf("newproc %x\n", np); 84 85 return np; 86 } 87 88 /* 89 * find a runnable process and switch to it. 90 */ 91 void 92 swtch() 93 { 94 struct proc *np; 95 96 while(1){ 97 for(np = curproc + 1; np != curproc; np++){ 98 if(np == &proc[NPROC]) 99 np = &proc[0]; 100 if(np->state == RUNNABLE) 101 break; 102 } 103 if(np->state == RUNNABLE) 104 break; 105 // idle... 106 } 107 108 curproc->ebp = read_ebp(); 109 curproc->esp = read_esp(); 110 111 cprintf("swtch %x -> %x\n", curproc, np); 112 113 curproc = np; 114 115 // XXX callee-saved registers? 116 117 // h/w sets busy bit in TSS descriptor sometimes, and faults 118 // if it's set in LTR. so clear tss descriptor busy bit. 119 curproc->gdt[SEG_TSS].sd_type = STS_T32A; 120 121 // XXX probably ought to lgdt on trap return too, in case 122 // a system call has moved a program or changed its size. 123 124 asm volatile("lgdt %0" : : "g" (np->gdt_pd.pd_lim)); 125 ltr(SEG_TSS << 3); 126 127 // this happens to work, but probably isn't safe: 128 // it's not clear that np->ebp is guaranteed to evaluate 129 // correctly after changing the stack pointer. 130 asm volatile("movl %0, %%esp" : : "g" (np->esp)); 131 asm volatile("movl %0, %%ebp" : : "g" (np->ebp)); 132 } 133 134 void 135 sleep(void *chan) 136 { 137 curproc->chan = chan; 138 curproc->state = WAITING; 139 swtch(); 140 } 141 142 void 143 wakeup(void *chan) 144 { 145 struct proc *p; 146 147 for(p = proc; p < &proc[NPROC]; p++) 148 if(p->state == WAITING && p->chan == chan) 149 p->state = RUNNABLE; 150 } 151