xref: /plan9-contrib/sys/src/9k/port/segment.c (revision 094d68186d4cdde21fdab9786d6c843a03693e4e)
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