xref: /xv6-public/proc.c (revision be0a7eac)
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