1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "../port/error.h"
7
8 Segment *
newseg(int type,uintptr base,uintptr top)9 newseg(int type, uintptr base, uintptr top)
10 {
11 Segment *s;
12 int mapsize;
13 usize size;
14
15 if((base|top) & (PGSZ-1))
16 panic("newseg");
17
18 size = (top-base)/PGSZ;
19 if(size > (SEGMAPSIZE*PTEPERTAB))
20 error(Enovmem);
21
22 s = smalloc(sizeof(Segment));
23 s->ref = 1;
24 s->type = type;
25 s->base = base;
26 s->top = top;
27 s->size = size;
28 s->lg2pgsize = PGSHFT;
29 s->ptemapmem = PTEPERTAB<<s->lg2pgsize;
30 s->sema.prev = &s->sema;
31 s->sema.next = &s->sema;
32
33 mapsize = HOWMANY(size, PTEPERTAB);
34 if(mapsize > nelem(s->ssegmap)){
35 mapsize *= 2;
36 if(mapsize > SEGMAPSIZE)
37 mapsize = SEGMAPSIZE;
38 s->map = smalloc(mapsize*sizeof(Pte*));
39 s->mapsize = mapsize;
40 }
41 else{
42 s->map = s->ssegmap;
43 s->mapsize = nelem(s->ssegmap);
44 }
45
46 return s;
47 }
48
49 void
putseg(Segment * s)50 putseg(Segment *s)
51 {
52 Pte **pp, **emap;
53 Image *i;
54
55 if(s == nil)
56 return;
57
58 i = s->image;
59 if(i != nil) {
60 lock(i);
61 lock(s);
62 if(i->s == s && s->ref == 1)
63 i->s = 0;
64 unlock(i);
65 }
66 else
67 lock(s);
68
69 s->ref--;
70 if(s->ref != 0) {
71 unlock(s);
72 return;
73 }
74 unlock(s);
75
76 qlock(&s->lk);
77 if(i)
78 putimage(i);
79
80 emap = &s->map[s->mapsize];
81 for(pp = s->map; pp < emap; pp++)
82 if(*pp != nil)
83 freepte(s, *pp);
84
85 qunlock(&s->lk);
86 if(s->map != s->ssegmap)
87 free(s->map);
88 if(s->profile != nil)
89 free(s->profile);
90 free(s);
91 }
92
93 void
relocateseg(Segment * s,uintptr offset)94 relocateseg(Segment *s, uintptr offset)
95 {
96 Page **pg, *x;
97 Pte *pte, **p, **endpte;
98
99 endpte = &s->map[s->mapsize];
100 for(p = s->map; p < endpte; p++) {
101 if(*p == 0)
102 continue;
103 pte = *p;
104 for(pg = pte->first; pg <= pte->last; pg++) {
105 if(x = *pg)
106 x->va += offset;
107 }
108 }
109 }
110
111 Segment*
dupseg(Segment ** seg,int segno,int share)112 dupseg(Segment **seg, int segno, int share)
113 {
114 int i, size;
115 Pte *pte;
116 Segment *n, *s;
117
118 SET(n);
119 s = seg[segno];
120
121 qlock(&s->lk);
122 if(waserror()){
123 qunlock(&s->lk);
124 nexterror();
125 }
126 switch(s->type&SG_TYPE) {
127 case SG_TEXT: /* New segment shares pte set */
128 case SG_SHARED:
129 case SG_PHYSICAL:
130 goto sameseg;
131
132 case SG_STACK:
133 n = newseg(s->type, s->base, s->top);
134 break;
135
136 case SG_BSS: /* Just copy on write */
137 if(share)
138 goto sameseg;
139 n = newseg(s->type, s->base, s->top);
140 break;
141
142 case SG_DATA: /* Copy on write plus demand load info */
143 if(segno == TSEG){
144 poperror();
145 qunlock(&s->lk);
146 return data2txt(s);
147 }
148
149 if(share)
150 goto sameseg;
151 n = newseg(s->type, s->base, s->top);
152
153 incref(s->image);
154 n->image = s->image;
155 n->fstart = s->fstart;
156 n->flen = s->flen;
157 n->lg2pgsize = s->lg2pgsize;
158 n->color = s->color;
159 break;
160 }
161 size = s->mapsize;
162 for(i = 0; i < size; i++)
163 if((pte = s->map[i]) != nil)
164 n->map[i] = ptecpy(pte);
165
166 n->flushme = s->flushme;
167 if(s->ref > 1)
168 procflushseg(s);
169 poperror();
170 qunlock(&s->lk);
171 return n;
172
173 sameseg:
174 incref(s);
175 poperror();
176 qunlock(&s->lk);
177 return s;
178 }
179
180 void
segpage(Segment * s,Page * p)181 segpage(Segment *s, Page *p)
182 {
183 Pte **pte;
184 uintptr soff;
185 Page **pg;
186
187 if(s->color == NOCOLOR)
188 s->color = p->color;
189
190 if(p->va < s->base || p->va >= s->top)
191 panic("segpage");
192
193 soff = p->va - s->base;
194 pte = &s->map[soff/s->ptemapmem];
195 if(*pte == 0)
196 *pte = ptealloc();
197
198 pg = &(*pte)->pages[(soff&(s->ptemapmem-1))>>s->lg2pgsize];
199 *pg = p;
200 if(pg < (*pte)->first)
201 (*pte)->first = pg;
202 if(pg > (*pte)->last)
203 (*pte)->last = pg;
204 }
205
206 /*
207 * called with s->lk locked
208 */
209 void
mfreeseg(Segment * s,uintptr start,uintptr top)210 mfreeseg(Segment *s, uintptr start, uintptr top)
211 {
212 int i, j, size;
213 usize pages;
214 uintptr soff;
215 Page *pg;
216 Page *list;
217
218 pages = (top-start)>>s->lg2pgsize;
219 soff = start-s->base;
220 j = (soff&(s->ptemapmem-1))>>s->lg2pgsize;
221
222 size = s->mapsize;
223 list = nil;
224 for(i = soff/s->ptemapmem; i < size; i++) {
225 if(pages <= 0)
226 break;
227 if(s->map[i] == 0) {
228 pages -= PTEPERTAB-j;
229 j = 0;
230 continue;
231 }
232 while(j < PTEPERTAB) {
233 pg = s->map[i]->pages[j];
234 /*
235 * We want to zero s->map[i]->page[j] and putpage(pg),
236 * but we have to make sure other processors flush the
237 * entry from their TLBs before the page is freed.
238 * We construct a list of the pages to be freed, zero
239 * the entries, then (below) call procflushseg, and call
240 * putpage on the whole list. If swapping were implemented,
241 * paged-out pages can't be in a TLB and could be disposed of here.
242 */
243 if(pg != nil){
244 pg->next = list;
245 list = pg;
246 s->map[i]->pages[j] = nil;
247 }
248 if(--pages == 0)
249 goto out;
250 j++;
251 }
252 j = 0;
253 }
254 out:
255 /* flush this seg in all other processes */
256 if(s->ref > 1)
257 procflushseg(s);
258
259 /* free the pages */
260 for(pg = list; pg != nil; pg = list){
261 list = list->next;
262 putpage(pg);
263 }
264 }
265
266 Segment*
isoverlap(Proc * p,uintptr va,usize len)267 isoverlap(Proc* p, uintptr va, usize len)
268 {
269 int i;
270 Segment *ns;
271 uintptr newtop;
272
273 newtop = va+len;
274 for(i = 0; i < NSEG; i++) {
275 ns = p->seg[i];
276 if(ns == nil)
277 continue;
278 if(newtop > ns->base && va < ns->top)
279 return ns;
280 }
281 return nil;
282 }
283
284 void
segclock(uintptr pc)285 segclock(uintptr pc)
286 {
287 Segment *s;
288
289 s = up->seg[TSEG];
290 if(s == nil || s->profile == nil)
291 return;
292
293 s->profile[0] += TK2MS(1);
294 if(pc >= s->base && pc < s->top) {
295 pc -= s->base;
296 s->profile[pc>>LRESPROF] += TK2MS(1);
297 }
298 }
299