xref: /minix3/minix/servers/vm/region.c (revision 89926a4cc3586a746814fd52d80a1e7dc60ffa53)
1433d6423SLionel Sambuc 
2433d6423SLionel Sambuc #include <minix/com.h>
3433d6423SLionel Sambuc #include <minix/callnr.h>
4433d6423SLionel Sambuc #include <minix/type.h>
5433d6423SLionel Sambuc #include <minix/config.h>
6433d6423SLionel Sambuc #include <minix/const.h>
7433d6423SLionel Sambuc #include <minix/sysutil.h>
8433d6423SLionel Sambuc #include <minix/syslib.h>
9433d6423SLionel Sambuc #include <minix/debug.h>
10433d6423SLionel Sambuc #include <minix/bitmap.h>
11433d6423SLionel Sambuc #include <minix/hash.h>
12433d6423SLionel Sambuc #include <machine/multiboot.h>
13433d6423SLionel Sambuc 
14433d6423SLionel Sambuc #include <sys/mman.h>
15433d6423SLionel Sambuc 
16433d6423SLionel Sambuc #include <limits.h>
17433d6423SLionel Sambuc #include <stdlib.h>
18433d6423SLionel Sambuc #include <string.h>
19433d6423SLionel Sambuc #include <assert.h>
20433d6423SLionel Sambuc #include <stdint.h>
21433d6423SLionel Sambuc #include <sys/param.h>
22433d6423SLionel Sambuc 
23433d6423SLionel Sambuc #include "vm.h"
24433d6423SLionel Sambuc #include "proto.h"
25433d6423SLionel Sambuc #include "util.h"
26433d6423SLionel Sambuc #include "glo.h"
27433d6423SLionel Sambuc #include "region.h"
28433d6423SLionel Sambuc #include "sanitycheck.h"
29433d6423SLionel Sambuc #include "memlist.h"
30433d6423SLionel Sambuc #include "memtype.h"
31433d6423SLionel Sambuc #include "regionavl.h"
32433d6423SLionel Sambuc 
33433d6423SLionel Sambuc static struct vir_region *map_copy_region(struct vmproc *vmp, struct
34433d6423SLionel Sambuc 	vir_region *vr);
35433d6423SLionel Sambuc 
map_region_init(void)36433d6423SLionel Sambuc void map_region_init(void)
37433d6423SLionel Sambuc {
38433d6423SLionel Sambuc }
39433d6423SLionel Sambuc 
map_printregion(struct vir_region * vr)40433d6423SLionel Sambuc static void map_printregion(struct vir_region *vr)
41433d6423SLionel Sambuc {
42433d6423SLionel Sambuc 	unsigned int i;
43433d6423SLionel Sambuc 	struct phys_region *ph;
44433d6423SLionel Sambuc 	printf("map_printmap: map_name: %s\n", vr->def_memtype->name);
45433d6423SLionel Sambuc 	printf("\t%lx (len 0x%lx, %lukB), %p, %s\n",
46433d6423SLionel Sambuc 		vr->vaddr, vr->length, vr->length/1024,
47433d6423SLionel Sambuc 		vr->def_memtype->name,
48433d6423SLionel Sambuc 		(vr->flags & VR_WRITABLE) ? "writable" : "readonly");
49433d6423SLionel Sambuc 	printf("\t\tphysblocks:\n");
50433d6423SLionel Sambuc 	for(i = 0; i < vr->length/VM_PAGE_SIZE; i++) {
51433d6423SLionel Sambuc 		if(!(ph=vr->physblocks[i])) continue;
52433d6423SLionel Sambuc 		printf("\t\t@ %lx (refs %d): phys 0x%lx, %s\n",
53433d6423SLionel Sambuc 			(vr->vaddr + ph->offset),
54433d6423SLionel Sambuc 			ph->ph->refcount, ph->ph->phys,
55433d6423SLionel Sambuc 		pt_writable(vr->parent, vr->vaddr + ph->offset) ? "W" : "R");
56433d6423SLionel Sambuc 
57433d6423SLionel Sambuc 	}
58433d6423SLionel Sambuc }
59433d6423SLionel Sambuc 
physblock_get(struct vir_region * region,vir_bytes offset)60433d6423SLionel Sambuc struct phys_region *physblock_get(struct vir_region *region, vir_bytes offset)
61433d6423SLionel Sambuc {
62433d6423SLionel Sambuc 	int i;
63433d6423SLionel Sambuc 	struct phys_region *foundregion;
64433d6423SLionel Sambuc 	assert(!(offset % VM_PAGE_SIZE));
65433d6423SLionel Sambuc 	assert( /* offset >= 0 && */ offset < region->length);
66433d6423SLionel Sambuc 	i = offset/VM_PAGE_SIZE;
67433d6423SLionel Sambuc 	if((foundregion =  region->physblocks[i]))
68433d6423SLionel Sambuc 		assert(foundregion->offset == offset);
69433d6423SLionel Sambuc 	return foundregion;
70433d6423SLionel Sambuc }
71433d6423SLionel Sambuc 
physblock_set(struct vir_region * region,vir_bytes offset,struct phys_region * newphysr)72433d6423SLionel Sambuc void physblock_set(struct vir_region *region, vir_bytes offset,
73433d6423SLionel Sambuc 	struct phys_region *newphysr)
74433d6423SLionel Sambuc {
75433d6423SLionel Sambuc 	int i;
76433d6423SLionel Sambuc 	struct vmproc *proc;
77433d6423SLionel Sambuc 	assert(!(offset % VM_PAGE_SIZE));
78433d6423SLionel Sambuc 	assert( /* offset >= 0 && */ offset < region->length);
79433d6423SLionel Sambuc 	i = offset/VM_PAGE_SIZE;
80433d6423SLionel Sambuc 	proc = region->parent;
81433d6423SLionel Sambuc 	assert(proc);
82433d6423SLionel Sambuc 	if(newphysr) {
83433d6423SLionel Sambuc 		assert(!region->physblocks[i]);
84433d6423SLionel Sambuc 		assert(newphysr->offset == offset);
85433d6423SLionel Sambuc 		proc->vm_total += VM_PAGE_SIZE;
86433d6423SLionel Sambuc 		if (proc->vm_total > proc->vm_total_max)
87433d6423SLionel Sambuc 			proc->vm_total_max = proc->vm_total;
88433d6423SLionel Sambuc 	} else {
89433d6423SLionel Sambuc 		assert(region->physblocks[i]);
90433d6423SLionel Sambuc 		proc->vm_total -= VM_PAGE_SIZE;
91433d6423SLionel Sambuc 	}
92433d6423SLionel Sambuc 	region->physblocks[i] = newphysr;
93433d6423SLionel Sambuc }
94433d6423SLionel Sambuc 
95433d6423SLionel Sambuc /*===========================================================================*
96433d6423SLionel Sambuc  *				map_printmap				     *
97433d6423SLionel Sambuc  *===========================================================================*/
map_printmap(struct vmproc * vmp)98433d6423SLionel Sambuc void map_printmap(struct vmproc *vmp)
99433d6423SLionel Sambuc {
100433d6423SLionel Sambuc 	struct vir_region *vr;
101433d6423SLionel Sambuc 	region_iter iter;
102433d6423SLionel Sambuc 
103433d6423SLionel Sambuc 	printf("memory regions in process %d:\n", vmp->vm_endpoint);
104433d6423SLionel Sambuc 
105433d6423SLionel Sambuc 	region_start_iter_least(&vmp->vm_regions_avl, &iter);
106433d6423SLionel Sambuc 	while((vr = region_get_iter(&iter))) {
107433d6423SLionel Sambuc 		map_printregion(vr);
108433d6423SLionel Sambuc 		region_incr_iter(&iter);
109433d6423SLionel Sambuc 	}
110433d6423SLionel Sambuc }
111433d6423SLionel Sambuc 
getnextvr(struct vir_region * vr)112433d6423SLionel Sambuc static struct vir_region *getnextvr(struct vir_region *vr)
113433d6423SLionel Sambuc {
114433d6423SLionel Sambuc 	struct vir_region *nextvr;
115433d6423SLionel Sambuc 	region_iter v_iter;
116433d6423SLionel Sambuc 	SLABSANE(vr);
117433d6423SLionel Sambuc 	region_start_iter(&vr->parent->vm_regions_avl, &v_iter, vr->vaddr, AVL_EQUAL);
118433d6423SLionel Sambuc 	assert(region_get_iter(&v_iter));
119433d6423SLionel Sambuc 	assert(region_get_iter(&v_iter) == vr);
120433d6423SLionel Sambuc 	region_incr_iter(&v_iter);
121433d6423SLionel Sambuc 	nextvr = region_get_iter(&v_iter);
122433d6423SLionel Sambuc 	if(!nextvr) return NULL;
123433d6423SLionel Sambuc 	SLABSANE(nextvr);
124433d6423SLionel Sambuc 	assert(vr->parent == nextvr->parent);
125433d6423SLionel Sambuc 	assert(vr->vaddr < nextvr->vaddr);
126433d6423SLionel Sambuc 	assert(vr->vaddr + vr->length <= nextvr->vaddr);
127433d6423SLionel Sambuc 	return nextvr;
128433d6423SLionel Sambuc }
129433d6423SLionel Sambuc 
pr_writable(struct vir_region * vr,struct phys_region * pr)130433d6423SLionel Sambuc static int pr_writable(struct vir_region *vr, struct phys_region *pr)
131433d6423SLionel Sambuc {
132433d6423SLionel Sambuc 	assert(pr->memtype->writable);
133433d6423SLionel Sambuc 	return ((vr->flags & VR_WRITABLE) && pr->memtype->writable(pr));
134433d6423SLionel Sambuc }
135433d6423SLionel Sambuc 
136433d6423SLionel Sambuc #if SANITYCHECKS
137433d6423SLionel Sambuc 
138433d6423SLionel Sambuc /*===========================================================================*
139433d6423SLionel Sambuc  *				map_sanitycheck_pt			     *
140433d6423SLionel Sambuc  *===========================================================================*/
map_sanitycheck_pt(struct vmproc * vmp,struct vir_region * vr,struct phys_region * pr)141433d6423SLionel Sambuc static int map_sanitycheck_pt(struct vmproc *vmp,
142433d6423SLionel Sambuc 	struct vir_region *vr, struct phys_region *pr)
143433d6423SLionel Sambuc {
144433d6423SLionel Sambuc 	struct phys_block *pb = pr->ph;
145433d6423SLionel Sambuc 	int rw;
146433d6423SLionel Sambuc 	int r;
147433d6423SLionel Sambuc 
148433d6423SLionel Sambuc 	if(pr_writable(vr, pr))
149433d6423SLionel Sambuc 		rw = PTF_WRITE;
150433d6423SLionel Sambuc 	else
151433d6423SLionel Sambuc 		rw = PTF_READ;
152433d6423SLionel Sambuc 
153433d6423SLionel Sambuc 	r = pt_writemap(vmp, &vmp->vm_pt, vr->vaddr + pr->offset,
154433d6423SLionel Sambuc 	  pb->phys, VM_PAGE_SIZE, PTF_PRESENT | PTF_USER | rw, WMF_VERIFY);
155433d6423SLionel Sambuc 
156433d6423SLionel Sambuc 	if(r != OK) {
157433d6423SLionel Sambuc 		printf("proc %d phys_region 0x%lx sanity check failed\n",
158433d6423SLionel Sambuc 			vmp->vm_endpoint, pr->offset);
159433d6423SLionel Sambuc 		map_printregion(vr);
160433d6423SLionel Sambuc 	}
161433d6423SLionel Sambuc 
162433d6423SLionel Sambuc 	return r;
163433d6423SLionel Sambuc }
164433d6423SLionel Sambuc 
165433d6423SLionel Sambuc /*===========================================================================*
166433d6423SLionel Sambuc  *				map_sanitycheck			     *
167433d6423SLionel Sambuc  *===========================================================================*/
map_sanitycheck(const char * file,int line)168433d6423SLionel Sambuc void map_sanitycheck(const char *file, int line)
169433d6423SLionel Sambuc {
170433d6423SLionel Sambuc 	struct vmproc *vmp;
171433d6423SLionel Sambuc 
172433d6423SLionel Sambuc /* Macro for looping over all physical blocks of all regions of
173433d6423SLionel Sambuc  * all processes.
174433d6423SLionel Sambuc  */
175433d6423SLionel Sambuc #define ALLREGIONS(regioncode, physcode)			\
176433d6423SLionel Sambuc 	for(vmp = vmproc; vmp < &vmproc[VMP_NR]; vmp++) {	\
177433d6423SLionel Sambuc 		vir_bytes voffset;				\
178433d6423SLionel Sambuc 		region_iter v_iter;				\
179433d6423SLionel Sambuc 		struct vir_region *vr;				\
180433d6423SLionel Sambuc 		if(!(vmp->vm_flags & VMF_INUSE))		\
181433d6423SLionel Sambuc 			continue;				\
182433d6423SLionel Sambuc 		region_start_iter_least(&vmp->vm_regions_avl, &v_iter);	\
183433d6423SLionel Sambuc 		while((vr = region_get_iter(&v_iter))) {	\
184433d6423SLionel Sambuc 			struct phys_region *pr;			\
185433d6423SLionel Sambuc 			regioncode;				\
186433d6423SLionel Sambuc 			for(voffset = 0; voffset < vr->length; \
187433d6423SLionel Sambuc 				voffset += VM_PAGE_SIZE) {	\
188433d6423SLionel Sambuc 				if(!(pr = physblock_get(vr, voffset))) 	\
189433d6423SLionel Sambuc 					continue;	\
190433d6423SLionel Sambuc 				physcode;			\
191433d6423SLionel Sambuc 			}					\
192433d6423SLionel Sambuc 			region_incr_iter(&v_iter);		\
193433d6423SLionel Sambuc 		}						\
194433d6423SLionel Sambuc 	}
195433d6423SLionel Sambuc 
196433d6423SLionel Sambuc #define MYSLABSANE(s) MYASSERT(slabsane_f(__FILE__, __LINE__, s, sizeof(*(s))))
197433d6423SLionel Sambuc 	/* Basic pointers check. */
198433d6423SLionel Sambuc 	ALLREGIONS(MYSLABSANE(vr),MYSLABSANE(pr); MYSLABSANE(pr->ph);MYSLABSANE(pr->parent));
199433d6423SLionel Sambuc 	ALLREGIONS(/* MYASSERT(vr->parent == vmp) */,MYASSERT(pr->parent == vr););
200433d6423SLionel Sambuc 
201433d6423SLionel Sambuc 	/* Do counting for consistency check. */
202433d6423SLionel Sambuc 	ALLREGIONS(;,USE(pr->ph, pr->ph->seencount = 0;););
203433d6423SLionel Sambuc 	ALLREGIONS(;,MYASSERT(pr->offset == voffset););
204433d6423SLionel Sambuc 	ALLREGIONS(;,USE(pr->ph, pr->ph->seencount++;);
205433d6423SLionel Sambuc 		if(pr->ph->seencount == 1) {
206433d6423SLionel Sambuc 			if(pr->memtype->ev_sanitycheck)
207433d6423SLionel Sambuc 				pr->memtype->ev_sanitycheck(pr, file, line);
208433d6423SLionel Sambuc 		}
209433d6423SLionel Sambuc 	);
210433d6423SLionel Sambuc 
211433d6423SLionel Sambuc 	/* Do consistency check. */
212433d6423SLionel Sambuc 	ALLREGIONS({ struct vir_region *nextvr = getnextvr(vr);
213433d6423SLionel Sambuc 		if(nextvr) {
214433d6423SLionel Sambuc 			MYASSERT(vr->vaddr < nextvr->vaddr);
215433d6423SLionel Sambuc 			MYASSERT(vr->vaddr + vr->length <= nextvr->vaddr);
216433d6423SLionel Sambuc 		}
217433d6423SLionel Sambuc 		}
218433d6423SLionel Sambuc 		MYASSERT(!(vr->vaddr % VM_PAGE_SIZE));,
219433d6423SLionel Sambuc 		if(pr->ph->flags & PBF_INCACHE) pr->ph->seencount++;
220433d6423SLionel Sambuc 		if(pr->ph->refcount != pr->ph->seencount) {
221433d6423SLionel Sambuc 			map_printmap(vmp);
222433d6423SLionel Sambuc 			printf("ph in vr %p: 0x%lx  refcount %u "
223433d6423SLionel Sambuc 				"but seencount %u\n",
224433d6423SLionel Sambuc 				vr, pr->offset,
225433d6423SLionel Sambuc 				pr->ph->refcount, pr->ph->seencount);
226433d6423SLionel Sambuc 		}
227433d6423SLionel Sambuc 		{
228433d6423SLionel Sambuc 			int n_others = 0;
229433d6423SLionel Sambuc 			struct phys_region *others;
230433d6423SLionel Sambuc 			if(pr->ph->refcount > 0) {
231433d6423SLionel Sambuc 				MYASSERT(pr->ph->firstregion);
232433d6423SLionel Sambuc 				if(pr->ph->refcount == 1) {
233433d6423SLionel Sambuc 					MYASSERT(pr->ph->firstregion == pr);
234433d6423SLionel Sambuc 				}
235433d6423SLionel Sambuc 			} else {
236433d6423SLionel Sambuc 				MYASSERT(!pr->ph->firstregion);
237433d6423SLionel Sambuc 			}
238433d6423SLionel Sambuc 			for(others = pr->ph->firstregion; others;
239433d6423SLionel Sambuc 				others = others->next_ph_list) {
240433d6423SLionel Sambuc 				MYSLABSANE(others);
241433d6423SLionel Sambuc 				MYASSERT(others->ph == pr->ph);
242433d6423SLionel Sambuc 				n_others++;
243433d6423SLionel Sambuc 			}
244433d6423SLionel Sambuc 			if(pr->ph->flags & PBF_INCACHE) n_others++;
245433d6423SLionel Sambuc 			MYASSERT(pr->ph->refcount == n_others);
246433d6423SLionel Sambuc 		}
247433d6423SLionel Sambuc 		MYASSERT(pr->ph->refcount == pr->ph->seencount);
248433d6423SLionel Sambuc 		MYASSERT(!(pr->offset % VM_PAGE_SIZE)););
249433d6423SLionel Sambuc 	ALLREGIONS(,MYASSERT(map_sanitycheck_pt(vmp, vr, pr) == OK));
250433d6423SLionel Sambuc }
251433d6423SLionel Sambuc 
252433d6423SLionel Sambuc #endif
253433d6423SLionel Sambuc 
254433d6423SLionel Sambuc /*=========================================================================*
255433d6423SLionel Sambuc  *				map_ph_writept				*
256433d6423SLionel Sambuc  *=========================================================================*/
map_ph_writept(struct vmproc * vmp,struct vir_region * vr,struct phys_region * pr)257433d6423SLionel Sambuc int map_ph_writept(struct vmproc *vmp, struct vir_region *vr,
258433d6423SLionel Sambuc 	struct phys_region *pr)
259433d6423SLionel Sambuc {
260433d6423SLionel Sambuc 	int flags = PTF_PRESENT | PTF_USER;
261433d6423SLionel Sambuc 	struct phys_block *pb = pr->ph;
262433d6423SLionel Sambuc 
263433d6423SLionel Sambuc 	assert(vr);
264433d6423SLionel Sambuc 	assert(pr);
265433d6423SLionel Sambuc 	assert(pb);
266433d6423SLionel Sambuc 
267433d6423SLionel Sambuc 	assert(!(vr->vaddr % VM_PAGE_SIZE));
268433d6423SLionel Sambuc 	assert(!(pr->offset % VM_PAGE_SIZE));
269433d6423SLionel Sambuc 	assert(pb->refcount > 0);
270433d6423SLionel Sambuc 
271433d6423SLionel Sambuc 	if(pr_writable(vr, pr))
272433d6423SLionel Sambuc 		flags |= PTF_WRITE;
273433d6423SLionel Sambuc 	else
274433d6423SLionel Sambuc 		flags |= PTF_READ;
275433d6423SLionel Sambuc 
276433d6423SLionel Sambuc 
277433d6423SLionel Sambuc 	if(vr->def_memtype->pt_flags)
278433d6423SLionel Sambuc 		flags |= vr->def_memtype->pt_flags(vr);
279433d6423SLionel Sambuc 
280433d6423SLionel Sambuc 	if(pt_writemap(vmp, &vmp->vm_pt, vr->vaddr + pr->offset,
281433d6423SLionel Sambuc 			pb->phys, VM_PAGE_SIZE, flags,
282433d6423SLionel Sambuc #if SANITYCHECKS
283433d6423SLionel Sambuc 	  	!pr->written ? 0 :
284433d6423SLionel Sambuc #endif
285433d6423SLionel Sambuc 	  	WMF_OVERWRITE) != OK) {
286433d6423SLionel Sambuc 	    printf("VM: map_writept: pt_writemap failed\n");
287433d6423SLionel Sambuc 	    return ENOMEM;
288433d6423SLionel Sambuc 	}
289433d6423SLionel Sambuc 
290433d6423SLionel Sambuc #if SANITYCHECKS
291433d6423SLionel Sambuc 	USE(pr, pr->written = 1;);
292433d6423SLionel Sambuc #endif
293433d6423SLionel Sambuc 
294433d6423SLionel Sambuc 	return OK;
295433d6423SLionel Sambuc }
296433d6423SLionel Sambuc 
297433d6423SLionel Sambuc #define SLOT_FAIL ((vir_bytes) -1)
298433d6423SLionel Sambuc 
299433d6423SLionel Sambuc /*===========================================================================*
300433d6423SLionel Sambuc  *				region_find_slot_range			     *
301433d6423SLionel Sambuc  *===========================================================================*/
region_find_slot_range(struct vmproc * vmp,vir_bytes minv,vir_bytes maxv,vir_bytes length)302433d6423SLionel Sambuc static vir_bytes region_find_slot_range(struct vmproc *vmp,
303433d6423SLionel Sambuc 		vir_bytes minv, vir_bytes maxv, vir_bytes length)
304433d6423SLionel Sambuc {
305433d6423SLionel Sambuc 	struct vir_region *lastregion;
306433d6423SLionel Sambuc 	vir_bytes startv = 0;
307433d6423SLionel Sambuc 	int foundflag = 0;
308433d6423SLionel Sambuc 	region_iter iter;
309433d6423SLionel Sambuc 
310433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
311433d6423SLionel Sambuc 
312433d6423SLionel Sambuc 	/* Length must be reasonable. */
313433d6423SLionel Sambuc 	assert(length > 0);
314433d6423SLionel Sambuc 
315433d6423SLionel Sambuc 	/* Special case: allow caller to set maxv to 0 meaning 'I want
316433d6423SLionel Sambuc 	 * it to be mapped in right here.'
317433d6423SLionel Sambuc 	 */
318433d6423SLionel Sambuc         if(maxv == 0) {
319433d6423SLionel Sambuc                 maxv = minv + length;
320433d6423SLionel Sambuc 
321433d6423SLionel Sambuc                 /* Sanity check. */
322433d6423SLionel Sambuc                 if(maxv <= minv) {
323433d6423SLionel Sambuc                         printf("region_find_slot: minv 0x%lx and bytes 0x%lx\n",
324433d6423SLionel Sambuc                                 minv, length);
325433d6423SLionel Sambuc                         return SLOT_FAIL;
326433d6423SLionel Sambuc                 }
327433d6423SLionel Sambuc         }
328433d6423SLionel Sambuc 
329433d6423SLionel Sambuc 	/* Basic input sanity checks. */
330433d6423SLionel Sambuc 	assert(!(length % VM_PAGE_SIZE));
331433d6423SLionel Sambuc 	if(minv >= maxv) {
332433d6423SLionel Sambuc 		printf("VM: 1 minv: 0x%lx maxv: 0x%lx length: 0x%lx\n",
333433d6423SLionel Sambuc 			minv, maxv, length);
334433d6423SLionel Sambuc 	}
335433d6423SLionel Sambuc 
336433d6423SLionel Sambuc 	assert(minv < maxv);
337433d6423SLionel Sambuc 
338433d6423SLionel Sambuc 	if(minv + length > maxv)
339433d6423SLionel Sambuc 		return SLOT_FAIL;
340433d6423SLionel Sambuc 
341433d6423SLionel Sambuc #define FREEVRANGE_TRY(rangestart, rangeend) {		\
342433d6423SLionel Sambuc 	vir_bytes frstart = (rangestart), frend = (rangeend);	\
343433d6423SLionel Sambuc 	frstart = MAX(frstart, minv);				\
344433d6423SLionel Sambuc 	frend   = MIN(frend, maxv);				\
345433d6423SLionel Sambuc 	if(frend > frstart && (frend - frstart) >= length) {	\
346433d6423SLionel Sambuc 		startv = frend-length;				\
347433d6423SLionel Sambuc 		foundflag = 1;					\
348433d6423SLionel Sambuc 	} }
349433d6423SLionel Sambuc 
350433d6423SLionel Sambuc #define FREEVRANGE(start, end) {					\
351433d6423SLionel Sambuc 	assert(!foundflag);						\
352433d6423SLionel Sambuc 	FREEVRANGE_TRY(((start)+VM_PAGE_SIZE), ((end)-VM_PAGE_SIZE));	\
353433d6423SLionel Sambuc 	if(!foundflag) {						\
354433d6423SLionel Sambuc 		FREEVRANGE_TRY((start), (end));				\
355433d6423SLionel Sambuc 	}								\
356433d6423SLionel Sambuc }
357433d6423SLionel Sambuc 
358433d6423SLionel Sambuc 	/* find region after maxv. */
359433d6423SLionel Sambuc 	region_start_iter(&vmp->vm_regions_avl, &iter, maxv, AVL_GREATER_EQUAL);
360433d6423SLionel Sambuc 	lastregion = region_get_iter(&iter);
361433d6423SLionel Sambuc 
362433d6423SLionel Sambuc 	if(!lastregion) {
363433d6423SLionel Sambuc 		/* This is the free virtual address space after the last region. */
364433d6423SLionel Sambuc 		region_start_iter(&vmp->vm_regions_avl, &iter, maxv, AVL_LESS);
365433d6423SLionel Sambuc 		lastregion = region_get_iter(&iter);
366433d6423SLionel Sambuc 		FREEVRANGE(lastregion ?
367433d6423SLionel Sambuc 			lastregion->vaddr+lastregion->length : 0, VM_DATATOP);
368433d6423SLionel Sambuc 	}
369433d6423SLionel Sambuc 
370433d6423SLionel Sambuc 	if(!foundflag) {
371433d6423SLionel Sambuc 		struct vir_region *vr;
372433d6423SLionel Sambuc 		while((vr = region_get_iter(&iter)) && !foundflag) {
373433d6423SLionel Sambuc 			struct vir_region *nextvr;
374433d6423SLionel Sambuc 			region_decr_iter(&iter);
375433d6423SLionel Sambuc 			nextvr = region_get_iter(&iter);
376433d6423SLionel Sambuc 			FREEVRANGE(nextvr ? nextvr->vaddr+nextvr->length : 0,
377433d6423SLionel Sambuc 			  vr->vaddr);
378433d6423SLionel Sambuc 		}
379433d6423SLionel Sambuc 	}
380433d6423SLionel Sambuc 
381433d6423SLionel Sambuc 	if(!foundflag) {
382433d6423SLionel Sambuc 		return SLOT_FAIL;
383433d6423SLionel Sambuc 	}
384433d6423SLionel Sambuc 
385433d6423SLionel Sambuc 	/* However we got it, startv must be in the requested range. */
386433d6423SLionel Sambuc 	assert(startv >= minv);
387433d6423SLionel Sambuc 	assert(startv < maxv);
388433d6423SLionel Sambuc 	assert(startv + length <= maxv);
389433d6423SLionel Sambuc 
390433d6423SLionel Sambuc 	/* remember this position as a hint for next time. */
391433d6423SLionel Sambuc 	vmp->vm_region_top = startv + length;
392433d6423SLionel Sambuc 
393433d6423SLionel Sambuc 	return startv;
394433d6423SLionel Sambuc }
395433d6423SLionel Sambuc 
396433d6423SLionel Sambuc /*===========================================================================*
397433d6423SLionel Sambuc  *				region_find_slot			     *
398433d6423SLionel Sambuc  *===========================================================================*/
region_find_slot(struct vmproc * vmp,vir_bytes minv,vir_bytes maxv,vir_bytes length)399433d6423SLionel Sambuc static vir_bytes region_find_slot(struct vmproc *vmp,
400433d6423SLionel Sambuc 		vir_bytes minv, vir_bytes maxv, vir_bytes length)
401433d6423SLionel Sambuc {
402433d6423SLionel Sambuc 	vir_bytes v, hint = vmp->vm_region_top;
403433d6423SLionel Sambuc 
404433d6423SLionel Sambuc 	/* use the top of the last inserted region as a minv hint if
405433d6423SLionel Sambuc 	 * possible. remember that a zero maxv is a special case.
406433d6423SLionel Sambuc 	 */
407433d6423SLionel Sambuc 
408433d6423SLionel Sambuc 	if(maxv && hint < maxv && hint >= minv) {
409433d6423SLionel Sambuc 		v = region_find_slot_range(vmp, minv, hint, length);
410433d6423SLionel Sambuc 
411433d6423SLionel Sambuc 		if(v != SLOT_FAIL)
412433d6423SLionel Sambuc 			return v;
413433d6423SLionel Sambuc 	}
414433d6423SLionel Sambuc 
415433d6423SLionel Sambuc 	return region_find_slot_range(vmp, minv, maxv, length);
416433d6423SLionel Sambuc }
417433d6423SLionel Sambuc 
phys_slot(vir_bytes len)418433d6423SLionel Sambuc static unsigned int phys_slot(vir_bytes len)
419433d6423SLionel Sambuc {
420433d6423SLionel Sambuc 	assert(!(len % VM_PAGE_SIZE));
421433d6423SLionel Sambuc 	return len / VM_PAGE_SIZE;
422433d6423SLionel Sambuc }
423433d6423SLionel Sambuc 
region_new(struct vmproc * vmp,vir_bytes startv,vir_bytes length,int flags,mem_type_t * memtype)424433d6423SLionel Sambuc static struct vir_region *region_new(struct vmproc *vmp, vir_bytes startv, vir_bytes length,
425433d6423SLionel Sambuc 	int flags, mem_type_t *memtype)
426433d6423SLionel Sambuc {
427433d6423SLionel Sambuc 	struct vir_region *newregion;
428433d6423SLionel Sambuc 	struct phys_region **newphysregions;
429433d6423SLionel Sambuc 	static u32_t id;
430433d6423SLionel Sambuc 	int slots = phys_slot(length);
431433d6423SLionel Sambuc 
432433d6423SLionel Sambuc 	if(!(SLABALLOC(newregion))) {
433433d6423SLionel Sambuc 		printf("vm: region_new: could not allocate\n");
434433d6423SLionel Sambuc 		return NULL;
435433d6423SLionel Sambuc 	}
436433d6423SLionel Sambuc 
437433d6423SLionel Sambuc 	/* Fill in node details. */
438433d6423SLionel Sambuc USE(newregion,
439433d6423SLionel Sambuc 	memset(newregion, 0, sizeof(*newregion));
440433d6423SLionel Sambuc 	newregion->vaddr = startv;
441433d6423SLionel Sambuc 	newregion->length = length;
442433d6423SLionel Sambuc 	newregion->flags = flags;
443433d6423SLionel Sambuc 	newregion->def_memtype = memtype;
444433d6423SLionel Sambuc 	newregion->remaps = 0;
445433d6423SLionel Sambuc 	newregion->id = id++;
446433d6423SLionel Sambuc 	newregion->lower = newregion->higher = NULL;
447433d6423SLionel Sambuc 	newregion->parent = vmp;);
448433d6423SLionel Sambuc 
449433d6423SLionel Sambuc 	if(!(newphysregions = calloc(slots, sizeof(struct phys_region *)))) {
450433d6423SLionel Sambuc 		printf("VM: region_new: allocating phys blocks failed\n");
451433d6423SLionel Sambuc 		SLABFREE(newregion);
452433d6423SLionel Sambuc 		return NULL;
453433d6423SLionel Sambuc 	}
454433d6423SLionel Sambuc 
455433d6423SLionel Sambuc 	USE(newregion, newregion->physblocks = newphysregions;);
456433d6423SLionel Sambuc 
457433d6423SLionel Sambuc 	return newregion;
458433d6423SLionel Sambuc }
459433d6423SLionel Sambuc 
460433d6423SLionel Sambuc /*===========================================================================*
461433d6423SLionel Sambuc  *				map_page_region				     *
462433d6423SLionel Sambuc  *===========================================================================*/
map_page_region(struct vmproc * vmp,vir_bytes minv,vir_bytes maxv,vir_bytes length,u32_t flags,int mapflags,mem_type_t * memtype)463433d6423SLionel Sambuc struct vir_region *map_page_region(struct vmproc *vmp, vir_bytes minv,
464433d6423SLionel Sambuc 	vir_bytes maxv, vir_bytes length, u32_t flags, int mapflags,
465433d6423SLionel Sambuc 	mem_type_t *memtype)
466433d6423SLionel Sambuc {
467433d6423SLionel Sambuc 	struct vir_region *newregion;
468433d6423SLionel Sambuc 	vir_bytes startv;
469433d6423SLionel Sambuc 
470433d6423SLionel Sambuc 	assert(!(length % VM_PAGE_SIZE));
471433d6423SLionel Sambuc 
472433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
473433d6423SLionel Sambuc 
474433d6423SLionel Sambuc 	startv = region_find_slot(vmp, minv, maxv, length);
475433d6423SLionel Sambuc 	if (startv == SLOT_FAIL)
476433d6423SLionel Sambuc 		return NULL;
477433d6423SLionel Sambuc 
478433d6423SLionel Sambuc 	/* Now we want a new region. */
479433d6423SLionel Sambuc 	if(!(newregion = region_new(vmp, startv, length, flags, memtype))) {
480433d6423SLionel Sambuc 		printf("VM: map_page_region: allocating region failed\n");
481433d6423SLionel Sambuc 		return NULL;
482433d6423SLionel Sambuc 	}
483433d6423SLionel Sambuc 
484433d6423SLionel Sambuc 	/* If a new event is specified, invoke it. */
485433d6423SLionel Sambuc 	if(newregion->def_memtype->ev_new) {
486433d6423SLionel Sambuc 		if(newregion->def_memtype->ev_new(newregion) != OK) {
487433d6423SLionel Sambuc 			/* ev_new will have freed and removed the region */
488433d6423SLionel Sambuc 			return NULL;
489433d6423SLionel Sambuc 		}
490433d6423SLionel Sambuc 	}
491433d6423SLionel Sambuc 
492433d6423SLionel Sambuc 	if(mapflags & MF_PREALLOC) {
493433d6423SLionel Sambuc 		if(map_handle_memory(vmp, newregion, 0, length, 1,
494433d6423SLionel Sambuc 			NULL, 0, 0) != OK) {
495433d6423SLionel Sambuc 			printf("VM: map_page_region: prealloc failed\n");
496f53651deSBen Gras 			map_free(newregion);
497433d6423SLionel Sambuc 			return NULL;
498433d6423SLionel Sambuc 		}
499433d6423SLionel Sambuc 	}
500433d6423SLionel Sambuc 
501433d6423SLionel Sambuc 	/* Pre-allocations should be uninitialized, but after that it's a
502433d6423SLionel Sambuc 	 * different story.
503433d6423SLionel Sambuc 	 */
504433d6423SLionel Sambuc 	USE(newregion, newregion->flags &= ~VR_UNINITIALIZED;);
505433d6423SLionel Sambuc 
506433d6423SLionel Sambuc 	/* Link it. */
507433d6423SLionel Sambuc 	region_insert(&vmp->vm_regions_avl, newregion);
508433d6423SLionel Sambuc 
509433d6423SLionel Sambuc #if SANITYCHECKS
510433d6423SLionel Sambuc 	assert(startv == newregion->vaddr);
511433d6423SLionel Sambuc 	{
512433d6423SLionel Sambuc 		struct vir_region *nextvr;
513433d6423SLionel Sambuc 		if((nextvr = getnextvr(newregion))) {
514433d6423SLionel Sambuc 			assert(newregion->vaddr < nextvr->vaddr);
515433d6423SLionel Sambuc 		}
516433d6423SLionel Sambuc 	}
517433d6423SLionel Sambuc #endif
518433d6423SLionel Sambuc 
519433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
520433d6423SLionel Sambuc 
521433d6423SLionel Sambuc 	return newregion;
522433d6423SLionel Sambuc }
523433d6423SLionel Sambuc 
524433d6423SLionel Sambuc /*===========================================================================*
525433d6423SLionel Sambuc  *				map_subfree				     *
526433d6423SLionel Sambuc  *===========================================================================*/
map_subfree(struct vir_region * region,vir_bytes start,vir_bytes len)527433d6423SLionel Sambuc static int map_subfree(struct vir_region *region,
528433d6423SLionel Sambuc 	vir_bytes start, vir_bytes len)
529433d6423SLionel Sambuc {
530433d6423SLionel Sambuc 	struct phys_region *pr;
531433d6423SLionel Sambuc 	vir_bytes end = start+len;
532433d6423SLionel Sambuc 	vir_bytes voffset;
533433d6423SLionel Sambuc 
534433d6423SLionel Sambuc #if SANITYCHECKS
535433d6423SLionel Sambuc 	SLABSANE(region);
536433d6423SLionel Sambuc 	for(voffset = 0; voffset < phys_slot(region->length);
537433d6423SLionel Sambuc 		voffset += VM_PAGE_SIZE) {
538433d6423SLionel Sambuc 		struct phys_region *others;
539433d6423SLionel Sambuc 		struct phys_block *pb;
540433d6423SLionel Sambuc 
541433d6423SLionel Sambuc 		if(!(pr = physblock_get(region, voffset)))
542433d6423SLionel Sambuc 			continue;
543433d6423SLionel Sambuc 
544433d6423SLionel Sambuc 		pb = pr->ph;
545433d6423SLionel Sambuc 
546433d6423SLionel Sambuc 		for(others = pb->firstregion; others;
547433d6423SLionel Sambuc 			others = others->next_ph_list) {
548433d6423SLionel Sambuc 			assert(others->ph == pb);
549433d6423SLionel Sambuc 		}
550433d6423SLionel Sambuc 	}
551433d6423SLionel Sambuc #endif
552433d6423SLionel Sambuc 
553433d6423SLionel Sambuc 	for(voffset = start; voffset < end; voffset+=VM_PAGE_SIZE) {
554433d6423SLionel Sambuc 		if(!(pr = physblock_get(region, voffset)))
555433d6423SLionel Sambuc 			continue;
556433d6423SLionel Sambuc 		assert(pr->offset >= start);
557433d6423SLionel Sambuc 		assert(pr->offset < end);
558433d6423SLionel Sambuc 		pb_unreferenced(region, pr, 1);
559433d6423SLionel Sambuc 		SLABFREE(pr);
560433d6423SLionel Sambuc 	}
561433d6423SLionel Sambuc 
562433d6423SLionel Sambuc 	return OK;
563433d6423SLionel Sambuc }
564433d6423SLionel Sambuc 
565433d6423SLionel Sambuc /*===========================================================================*
566433d6423SLionel Sambuc  *				map_free				     *
567433d6423SLionel Sambuc  *===========================================================================*/
map_free(struct vir_region * region)568433d6423SLionel Sambuc int map_free(struct vir_region *region)
569433d6423SLionel Sambuc {
570433d6423SLionel Sambuc 	int r;
571433d6423SLionel Sambuc 
572433d6423SLionel Sambuc 	if((r=map_subfree(region, 0, region->length)) != OK) {
573433d6423SLionel Sambuc 		printf("%d\n", __LINE__);
574433d6423SLionel Sambuc 		return r;
575433d6423SLionel Sambuc 	}
576433d6423SLionel Sambuc 
577433d6423SLionel Sambuc 	if(region->def_memtype->ev_delete)
578433d6423SLionel Sambuc 		region->def_memtype->ev_delete(region);
579433d6423SLionel Sambuc 	free(region->physblocks);
580433d6423SLionel Sambuc 	region->physblocks = NULL;
581433d6423SLionel Sambuc 	SLABFREE(region);
582433d6423SLionel Sambuc 
583433d6423SLionel Sambuc 	return OK;
584433d6423SLionel Sambuc }
585433d6423SLionel Sambuc 
586433d6423SLionel Sambuc /*========================================================================*
587433d6423SLionel Sambuc  *				map_free_proc				  *
588433d6423SLionel Sambuc  *========================================================================*/
map_free_proc(struct vmproc * vmp)589433d6423SLionel Sambuc int map_free_proc(struct vmproc *vmp)
590433d6423SLionel Sambuc {
591433d6423SLionel Sambuc 	struct vir_region *r;
592433d6423SLionel Sambuc 
593433d6423SLionel Sambuc 	while((r = region_search_root(&vmp->vm_regions_avl))) {
594433d6423SLionel Sambuc 		SANITYCHECK(SCL_DETAIL);
595433d6423SLionel Sambuc #if SANITYCHECKS
596433d6423SLionel Sambuc 		nocheck++;
597433d6423SLionel Sambuc #endif
598433d6423SLionel Sambuc 		region_remove(&vmp->vm_regions_avl, r->vaddr); /* For sanity checks. */
599433d6423SLionel Sambuc 		map_free(r);
600433d6423SLionel Sambuc #if SANITYCHECKS
601433d6423SLionel Sambuc 		nocheck--;
602433d6423SLionel Sambuc #endif
603433d6423SLionel Sambuc 		SANITYCHECK(SCL_DETAIL);
604433d6423SLionel Sambuc 	}
605433d6423SLionel Sambuc 
606433d6423SLionel Sambuc 	region_init(&vmp->vm_regions_avl);
607433d6423SLionel Sambuc 
608433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
609433d6423SLionel Sambuc 
610433d6423SLionel Sambuc 	return OK;
611433d6423SLionel Sambuc }
612433d6423SLionel Sambuc 
613433d6423SLionel Sambuc /*===========================================================================*
614433d6423SLionel Sambuc  *				map_lookup				     *
615433d6423SLionel Sambuc  *===========================================================================*/
map_lookup(struct vmproc * vmp,vir_bytes offset,struct phys_region ** physr)616433d6423SLionel Sambuc struct vir_region *map_lookup(struct vmproc *vmp,
617433d6423SLionel Sambuc 	vir_bytes offset, struct phys_region **physr)
618433d6423SLionel Sambuc {
619433d6423SLionel Sambuc 	struct vir_region *r;
620433d6423SLionel Sambuc 
621433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
622433d6423SLionel Sambuc 
623433d6423SLionel Sambuc #if SANITYCHECKS
624433d6423SLionel Sambuc 	if(!region_search_root(&vmp->vm_regions_avl))
625433d6423SLionel Sambuc 		panic("process has no regions: %d", vmp->vm_endpoint);
626433d6423SLionel Sambuc #endif
627433d6423SLionel Sambuc 
628433d6423SLionel Sambuc 	if((r = region_search(&vmp->vm_regions_avl, offset, AVL_LESS_EQUAL))) {
629433d6423SLionel Sambuc 		vir_bytes ph;
630433d6423SLionel Sambuc 		if(offset >= r->vaddr && offset < r->vaddr + r->length) {
631433d6423SLionel Sambuc 			ph = offset - r->vaddr;
632433d6423SLionel Sambuc 			if(physr) {
633433d6423SLionel Sambuc 				*physr = physblock_get(r, ph);
634433d6423SLionel Sambuc 				if(*physr) assert((*physr)->offset == ph);
635433d6423SLionel Sambuc 			}
636433d6423SLionel Sambuc 			return r;
637433d6423SLionel Sambuc 		}
638433d6423SLionel Sambuc 	}
639433d6423SLionel Sambuc 
640433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
641433d6423SLionel Sambuc 
642433d6423SLionel Sambuc 	return NULL;
643433d6423SLionel Sambuc }
644433d6423SLionel Sambuc 
vrallocflags(u32_t flags)645433d6423SLionel Sambuc u32_t vrallocflags(u32_t flags)
646433d6423SLionel Sambuc {
647433d6423SLionel Sambuc 	u32_t allocflags = 0;
648433d6423SLionel Sambuc 
649433d6423SLionel Sambuc 	if(flags & VR_PHYS64K)
650433d6423SLionel Sambuc 		allocflags |= PAF_ALIGN64K;
651433d6423SLionel Sambuc 	if(flags & VR_LOWER16MB)
652433d6423SLionel Sambuc 		allocflags |= PAF_LOWER16MB;
653433d6423SLionel Sambuc 	if(flags & VR_LOWER1MB)
654433d6423SLionel Sambuc 		allocflags |= PAF_LOWER1MB;
655433d6423SLionel Sambuc 	if(!(flags & VR_UNINITIALIZED))
656433d6423SLionel Sambuc 		allocflags |= PAF_CLEAR;
657433d6423SLionel Sambuc 
658433d6423SLionel Sambuc 	return allocflags;
659433d6423SLionel Sambuc }
660433d6423SLionel Sambuc 
661433d6423SLionel Sambuc /*===========================================================================*
662433d6423SLionel Sambuc  *				map_pf			     *
663433d6423SLionel Sambuc  *===========================================================================*/
map_pf(struct vmproc * vmp,struct vir_region * region,vir_bytes offset,int write,vfs_callback_t pf_callback,void * state,int len,int * io)664433d6423SLionel Sambuc int map_pf(struct vmproc *vmp,
665433d6423SLionel Sambuc 	struct vir_region *region,
666433d6423SLionel Sambuc 	vir_bytes offset,
667433d6423SLionel Sambuc 	int write,
668433d6423SLionel Sambuc 	vfs_callback_t pf_callback,
669433d6423SLionel Sambuc 	void *state,
670433d6423SLionel Sambuc 	int len,
671433d6423SLionel Sambuc 	int *io)
672433d6423SLionel Sambuc {
673433d6423SLionel Sambuc 	struct phys_region *ph;
674433d6423SLionel Sambuc 	int r = OK;
675433d6423SLionel Sambuc 
676433d6423SLionel Sambuc 	offset -= offset % VM_PAGE_SIZE;
677433d6423SLionel Sambuc 
678433d6423SLionel Sambuc /*	assert(offset >= 0); */ /* always true */
679433d6423SLionel Sambuc 	assert(offset < region->length);
680433d6423SLionel Sambuc 
681433d6423SLionel Sambuc 	assert(!(region->vaddr % VM_PAGE_SIZE));
682433d6423SLionel Sambuc 	assert(!(write && !(region->flags & VR_WRITABLE)));
683433d6423SLionel Sambuc 
684433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
685433d6423SLionel Sambuc 
686433d6423SLionel Sambuc 	if(!(ph = physblock_get(region, offset))) {
687433d6423SLionel Sambuc 		struct phys_block *pb;
688433d6423SLionel Sambuc 
689433d6423SLionel Sambuc 		/* New block. */
690433d6423SLionel Sambuc 
691433d6423SLionel Sambuc 		if(!(pb = pb_new(MAP_NONE))) {
692433d6423SLionel Sambuc 			printf("map_pf: pb_new failed\n");
693433d6423SLionel Sambuc 			return ENOMEM;
694433d6423SLionel Sambuc 		}
695433d6423SLionel Sambuc 
696433d6423SLionel Sambuc 		if(!(ph = pb_reference(pb, offset, region,
697433d6423SLionel Sambuc 			region->def_memtype))) {
698433d6423SLionel Sambuc 			printf("map_pf: pb_reference failed\n");
699433d6423SLionel Sambuc 			pb_free(pb);
700433d6423SLionel Sambuc 			return ENOMEM;
701433d6423SLionel Sambuc 		}
702433d6423SLionel Sambuc 	}
703433d6423SLionel Sambuc 
704433d6423SLionel Sambuc 	assert(ph);
705433d6423SLionel Sambuc 	assert(ph->ph);
706433d6423SLionel Sambuc 
707433d6423SLionel Sambuc 	/* If we're writing and the block is already
708433d6423SLionel Sambuc 	 * writable, nothing to do.
709433d6423SLionel Sambuc 	 */
710433d6423SLionel Sambuc 
711433d6423SLionel Sambuc 	assert(ph->memtype->writable);
712433d6423SLionel Sambuc 
713433d6423SLionel Sambuc 	if(!write || !ph->memtype->writable(ph)) {
714433d6423SLionel Sambuc 		assert(ph->memtype->ev_pagefault);
715433d6423SLionel Sambuc 		assert(ph->ph);
716433d6423SLionel Sambuc 
717433d6423SLionel Sambuc 		if((r = ph->memtype->ev_pagefault(vmp,
718433d6423SLionel Sambuc 			region, ph, write, pf_callback, state, len, io)) == SUSPEND) {
719433d6423SLionel Sambuc 			return SUSPEND;
720433d6423SLionel Sambuc 		}
721433d6423SLionel Sambuc 
722433d6423SLionel Sambuc 		if(r != OK) {
723433d6423SLionel Sambuc #if 0
724433d6423SLionel Sambuc 			printf("map_pf: pagefault in %s failed\n", ph->memtype->name);
725433d6423SLionel Sambuc #endif
726433d6423SLionel Sambuc 			if(ph)
727433d6423SLionel Sambuc 				pb_unreferenced(region, ph, 1);
728433d6423SLionel Sambuc 			return r;
729433d6423SLionel Sambuc 		}
730433d6423SLionel Sambuc 
731433d6423SLionel Sambuc 		assert(ph);
732433d6423SLionel Sambuc 		assert(ph->ph);
733433d6423SLionel Sambuc 		assert(ph->ph->phys != MAP_NONE);
734433d6423SLionel Sambuc 	}
735433d6423SLionel Sambuc 
736433d6423SLionel Sambuc 	assert(ph->ph);
737433d6423SLionel Sambuc 	assert(ph->ph->phys != MAP_NONE);
738433d6423SLionel Sambuc 
739433d6423SLionel Sambuc 	if((r = map_ph_writept(vmp, region, ph)) != OK) {
740433d6423SLionel Sambuc 		printf("map_pf: writept failed\n");
741433d6423SLionel Sambuc 		return r;
742433d6423SLionel Sambuc 	}
743433d6423SLionel Sambuc 
744433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
745433d6423SLionel Sambuc 
746433d6423SLionel Sambuc #if SANITYCHECKS
747433d6423SLionel Sambuc 	if(OK != pt_checkrange(&vmp->vm_pt, region->vaddr+offset,
748433d6423SLionel Sambuc 		VM_PAGE_SIZE, write)) {
749433d6423SLionel Sambuc 		panic("map_pf: pt_checkrange failed: %d", r);
750433d6423SLionel Sambuc 	}
751433d6423SLionel Sambuc #endif
752433d6423SLionel Sambuc 
753433d6423SLionel Sambuc 	return r;
754433d6423SLionel Sambuc }
755433d6423SLionel Sambuc 
map_handle_memory(struct vmproc * vmp,struct vir_region * region,vir_bytes start_offset,vir_bytes length,int write,vfs_callback_t cb,void * state,int statelen)756433d6423SLionel Sambuc int map_handle_memory(struct vmproc *vmp,
757433d6423SLionel Sambuc 	struct vir_region *region, vir_bytes start_offset, vir_bytes length,
758433d6423SLionel Sambuc 	int write, vfs_callback_t cb, void *state, int statelen)
759433d6423SLionel Sambuc {
760433d6423SLionel Sambuc 	vir_bytes offset, lim;
761433d6423SLionel Sambuc 	int r;
762433d6423SLionel Sambuc 	int io = 0;
763433d6423SLionel Sambuc 
764433d6423SLionel Sambuc 	assert(length > 0);
765433d6423SLionel Sambuc 	lim = start_offset + length;
766433d6423SLionel Sambuc 	assert(lim > start_offset);
767433d6423SLionel Sambuc 
768433d6423SLionel Sambuc 	for(offset = start_offset; offset < lim; offset += VM_PAGE_SIZE)
769433d6423SLionel Sambuc 		if((r = map_pf(vmp, region, offset, write,
770433d6423SLionel Sambuc 		   cb, state, statelen, &io)) != OK)
771433d6423SLionel Sambuc 			return r;
772433d6423SLionel Sambuc 
773433d6423SLionel Sambuc 	return OK;
774433d6423SLionel Sambuc }
775433d6423SLionel Sambuc 
776433d6423SLionel Sambuc /*===========================================================================*
777433d6423SLionel Sambuc  *				map_pin_memory      			     *
778433d6423SLionel Sambuc  *===========================================================================*/
map_pin_memory(struct vmproc * vmp)779433d6423SLionel Sambuc int map_pin_memory(struct vmproc *vmp)
780433d6423SLionel Sambuc {
781433d6423SLionel Sambuc 	struct vir_region *vr;
782433d6423SLionel Sambuc 	int r;
783433d6423SLionel Sambuc 	region_iter iter;
784433d6423SLionel Sambuc 	region_start_iter_least(&vmp->vm_regions_avl, &iter);
785433d6423SLionel Sambuc 	/* Scan all memory regions. */
78610e6ba68SBen Gras 	pt_assert(&vmp->vm_pt);
787433d6423SLionel Sambuc 	while((vr = region_get_iter(&iter))) {
788433d6423SLionel Sambuc 		/* Make sure region is mapped to physical memory and writable.*/
789433d6423SLionel Sambuc 		r = map_handle_memory(vmp, vr, 0, vr->length, 1, NULL, 0, 0);
790433d6423SLionel Sambuc 		if(r != OK) {
791433d6423SLionel Sambuc 		    panic("map_pin_memory: map_handle_memory failed: %d", r);
792433d6423SLionel Sambuc 		}
793433d6423SLionel Sambuc 		region_incr_iter(&iter);
794433d6423SLionel Sambuc 	}
79510e6ba68SBen Gras 	pt_assert(&vmp->vm_pt);
796433d6423SLionel Sambuc 	return OK;
797433d6423SLionel Sambuc }
798433d6423SLionel Sambuc 
799433d6423SLionel Sambuc /*===========================================================================*
800433d6423SLionel Sambuc  *				map_copy_region			     	*
801433d6423SLionel Sambuc  *===========================================================================*/
map_copy_region(struct vmproc * vmp,struct vir_region * vr)802433d6423SLionel Sambuc struct vir_region *map_copy_region(struct vmproc *vmp, struct vir_region *vr)
803433d6423SLionel Sambuc {
804433d6423SLionel Sambuc 	/* map_copy_region creates a complete copy of the vir_region
805433d6423SLionel Sambuc 	 * data structure, linking in the same phys_blocks directly,
806433d6423SLionel Sambuc 	 * but all in limbo, i.e., the caller has to link the vir_region
807433d6423SLionel Sambuc 	 * to a process. Therefore it doesn't increase the refcount in
808433d6423SLionel Sambuc 	 * the phys_block; the caller has to do this once it's linked.
809433d6423SLionel Sambuc 	 * The reason for this is to keep the sanity checks working
810433d6423SLionel Sambuc 	 * within this function.
811433d6423SLionel Sambuc 	 */
812433d6423SLionel Sambuc 	struct vir_region *newvr;
813433d6423SLionel Sambuc 	struct phys_region *ph;
814433d6423SLionel Sambuc 	int r;
815433d6423SLionel Sambuc #if SANITYCHECKS
816433d6423SLionel Sambuc 	unsigned int cr;
817433d6423SLionel Sambuc 	cr = physregions(vr);
818433d6423SLionel Sambuc #endif
819433d6423SLionel Sambuc 	vir_bytes p;
820433d6423SLionel Sambuc 
821433d6423SLionel Sambuc 	if(!(newvr = region_new(vr->parent, vr->vaddr, vr->length, vr->flags, vr->def_memtype)))
822433d6423SLionel Sambuc 		return NULL;
823433d6423SLionel Sambuc 
824433d6423SLionel Sambuc 	USE(newvr, newvr->parent = vmp;);
825433d6423SLionel Sambuc 
826433d6423SLionel Sambuc 	if(vr->def_memtype->ev_copy && (r=vr->def_memtype->ev_copy(vr, newvr)) != OK) {
827433d6423SLionel Sambuc 		map_free(newvr);
828433d6423SLionel Sambuc 		printf("VM: memtype-specific copy failed (%d)\n", r);
829433d6423SLionel Sambuc 		return NULL;
830433d6423SLionel Sambuc 	}
831433d6423SLionel Sambuc 
832433d6423SLionel Sambuc 	for(p = 0; p < phys_slot(vr->length); p++) {
833433d6423SLionel Sambuc 		struct phys_region *newph;
834433d6423SLionel Sambuc 
835433d6423SLionel Sambuc 		if(!(ph = physblock_get(vr, p*VM_PAGE_SIZE))) continue;
836433d6423SLionel Sambuc 		newph = pb_reference(ph->ph, ph->offset, newvr,
837433d6423SLionel Sambuc 			vr->def_memtype);
838433d6423SLionel Sambuc 
839433d6423SLionel Sambuc 		if(!newph) { map_free(newvr); return NULL; }
840433d6423SLionel Sambuc 
841433d6423SLionel Sambuc 		if(ph->memtype->ev_reference)
842433d6423SLionel Sambuc 			ph->memtype->ev_reference(ph, newph);
843433d6423SLionel Sambuc 
844433d6423SLionel Sambuc #if SANITYCHECKS
845433d6423SLionel Sambuc 		USE(newph, newph->written = 0;);
846433d6423SLionel Sambuc 		assert(physregions(vr) == cr);
847433d6423SLionel Sambuc #endif
848433d6423SLionel Sambuc 	}
849433d6423SLionel Sambuc 
850433d6423SLionel Sambuc #if SANITYCHECKS
851433d6423SLionel Sambuc 	assert(physregions(vr) == physregions(newvr));
852433d6423SLionel Sambuc #endif
853433d6423SLionel Sambuc 
854433d6423SLionel Sambuc 	return newvr;
855433d6423SLionel Sambuc }
856433d6423SLionel Sambuc 
857433d6423SLionel Sambuc /*===========================================================================*
858433d6423SLionel Sambuc  *				copy_abs2region			     	*
859433d6423SLionel Sambuc  *===========================================================================*/
copy_abs2region(phys_bytes absaddr,struct vir_region * destregion,phys_bytes offset,phys_bytes len)860433d6423SLionel Sambuc int copy_abs2region(phys_bytes absaddr, struct vir_region *destregion,
861433d6423SLionel Sambuc 	phys_bytes offset, phys_bytes len)
862433d6423SLionel Sambuc 
863433d6423SLionel Sambuc {
864433d6423SLionel Sambuc 	assert(destregion);
865433d6423SLionel Sambuc 	assert(destregion->physblocks);
866433d6423SLionel Sambuc 	while(len > 0) {
867433d6423SLionel Sambuc 		phys_bytes sublen, suboffset;
868433d6423SLionel Sambuc 		struct phys_region *ph;
869433d6423SLionel Sambuc 		assert(destregion);
870433d6423SLionel Sambuc 		assert(destregion->physblocks);
871433d6423SLionel Sambuc 		if(!(ph = physblock_get(destregion, offset))) {
872433d6423SLionel Sambuc 			printf("VM: copy_abs2region: no phys region found (1).\n");
873433d6423SLionel Sambuc 			return EFAULT;
874433d6423SLionel Sambuc 		}
875433d6423SLionel Sambuc 		assert(ph->offset <= offset);
876433d6423SLionel Sambuc 		if(ph->offset+VM_PAGE_SIZE <= offset) {
877433d6423SLionel Sambuc 			printf("VM: copy_abs2region: no phys region found (2).\n");
878433d6423SLionel Sambuc 			return EFAULT;
879433d6423SLionel Sambuc 		}
880433d6423SLionel Sambuc 		suboffset = offset - ph->offset;
881433d6423SLionel Sambuc 		assert(suboffset < VM_PAGE_SIZE);
882433d6423SLionel Sambuc 		sublen = len;
883433d6423SLionel Sambuc 		if(sublen > VM_PAGE_SIZE - suboffset)
884433d6423SLionel Sambuc 			sublen = VM_PAGE_SIZE - suboffset;
885433d6423SLionel Sambuc 		assert(suboffset + sublen <= VM_PAGE_SIZE);
886433d6423SLionel Sambuc 		if(ph->ph->refcount != 1) {
887433d6423SLionel Sambuc 			printf("VM: copy_abs2region: refcount not 1.\n");
888433d6423SLionel Sambuc 			return EFAULT;
889433d6423SLionel Sambuc 		}
890433d6423SLionel Sambuc 
891433d6423SLionel Sambuc 		if(sys_abscopy(absaddr, ph->ph->phys + suboffset, sublen) != OK) {
892433d6423SLionel Sambuc 			printf("VM: copy_abs2region: abscopy failed.\n");
893433d6423SLionel Sambuc 			return EFAULT;
894433d6423SLionel Sambuc 		}
895433d6423SLionel Sambuc 		absaddr += sublen;
896433d6423SLionel Sambuc 		offset += sublen;
897433d6423SLionel Sambuc 		len -= sublen;
898433d6423SLionel Sambuc 	}
899433d6423SLionel Sambuc 
900433d6423SLionel Sambuc 	return OK;
901433d6423SLionel Sambuc }
902433d6423SLionel Sambuc 
903433d6423SLionel Sambuc /*=========================================================================*
904433d6423SLionel Sambuc  *				map_writept				*
905433d6423SLionel Sambuc  *=========================================================================*/
map_writept(struct vmproc * vmp)906433d6423SLionel Sambuc int map_writept(struct vmproc *vmp)
907433d6423SLionel Sambuc {
908433d6423SLionel Sambuc 	struct vir_region *vr;
909433d6423SLionel Sambuc 	struct phys_region *ph;
910433d6423SLionel Sambuc 	int r;
911433d6423SLionel Sambuc 	region_iter v_iter;
912433d6423SLionel Sambuc 	region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
913433d6423SLionel Sambuc 
914433d6423SLionel Sambuc 	while((vr = region_get_iter(&v_iter))) {
915433d6423SLionel Sambuc 		vir_bytes p;
916433d6423SLionel Sambuc 		for(p = 0; p < vr->length; p += VM_PAGE_SIZE) {
917433d6423SLionel Sambuc 			if(!(ph = physblock_get(vr, p))) continue;
918433d6423SLionel Sambuc 
919433d6423SLionel Sambuc 			if((r=map_ph_writept(vmp, vr, ph)) != OK) {
920433d6423SLionel Sambuc 				printf("VM: map_writept: failed\n");
921433d6423SLionel Sambuc 				return r;
922433d6423SLionel Sambuc 			}
923433d6423SLionel Sambuc 		}
924433d6423SLionel Sambuc 		region_incr_iter(&v_iter);
925433d6423SLionel Sambuc 	}
926433d6423SLionel Sambuc 
927433d6423SLionel Sambuc 	return OK;
928433d6423SLionel Sambuc }
929433d6423SLionel Sambuc 
930433d6423SLionel Sambuc /*========================================================================*
931433d6423SLionel Sambuc  *			       map_proc_copy			     	  *
932433d6423SLionel Sambuc  *========================================================================*/
map_proc_copy(struct vmproc * dst,struct vmproc * src)933433d6423SLionel Sambuc int map_proc_copy(struct vmproc *dst, struct vmproc *src)
934433d6423SLionel Sambuc {
935433d6423SLionel Sambuc /* Copy all the memory regions from the src process to the dst process. */
936433d6423SLionel Sambuc 	region_init(&dst->vm_regions_avl);
937433d6423SLionel Sambuc 
93863483e02SCristiano Giuffrida 	return map_proc_copy_range(dst, src, NULL, NULL);
939433d6423SLionel Sambuc }
940433d6423SLionel Sambuc 
941433d6423SLionel Sambuc /*========================================================================*
94263483e02SCristiano Giuffrida  *			     map_proc_copy_range			     	  *
943433d6423SLionel Sambuc  *========================================================================*/
map_proc_copy_range(struct vmproc * dst,struct vmproc * src,struct vir_region * start_src_vr,struct vir_region * end_src_vr)94463483e02SCristiano Giuffrida int map_proc_copy_range(struct vmproc *dst, struct vmproc *src,
94563483e02SCristiano Giuffrida 	struct vir_region *start_src_vr, struct vir_region *end_src_vr)
946433d6423SLionel Sambuc {
947433d6423SLionel Sambuc 	struct vir_region *vr;
948433d6423SLionel Sambuc 	region_iter v_iter;
949433d6423SLionel Sambuc 
950433d6423SLionel Sambuc 	if(!start_src_vr)
951433d6423SLionel Sambuc 		start_src_vr = region_search_least(&src->vm_regions_avl);
95263483e02SCristiano Giuffrida 	if(!end_src_vr)
95363483e02SCristiano Giuffrida 		end_src_vr = region_search_greatest(&src->vm_regions_avl);
954433d6423SLionel Sambuc 
95563483e02SCristiano Giuffrida 	assert(start_src_vr && end_src_vr);
956433d6423SLionel Sambuc 	assert(start_src_vr->parent == src);
957433d6423SLionel Sambuc 	region_start_iter(&src->vm_regions_avl, &v_iter,
958433d6423SLionel Sambuc 		start_src_vr->vaddr, AVL_EQUAL);
959433d6423SLionel Sambuc 	assert(region_get_iter(&v_iter) == start_src_vr);
960433d6423SLionel Sambuc 
96163483e02SCristiano Giuffrida 	/* Copy source regions into the destination. */
962433d6423SLionel Sambuc 
963433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
964433d6423SLionel Sambuc 
965433d6423SLionel Sambuc 	while((vr = region_get_iter(&v_iter))) {
966433d6423SLionel Sambuc 		struct vir_region *newvr;
967433d6423SLionel Sambuc 		if(!(newvr = map_copy_region(dst, vr))) {
968433d6423SLionel Sambuc 			map_free_proc(dst);
969433d6423SLionel Sambuc 			return ENOMEM;
970433d6423SLionel Sambuc 		}
971433d6423SLionel Sambuc 		region_insert(&dst->vm_regions_avl, newvr);
972433d6423SLionel Sambuc 		assert(vr->length == newvr->length);
973433d6423SLionel Sambuc 
974433d6423SLionel Sambuc #if SANITYCHECKS
975433d6423SLionel Sambuc 	{
976433d6423SLionel Sambuc 		vir_bytes vaddr;
977433d6423SLionel Sambuc 		struct phys_region *orig_ph, *new_ph;
978433d6423SLionel Sambuc 		assert(vr->physblocks != newvr->physblocks);
979433d6423SLionel Sambuc 		for(vaddr = 0; vaddr < vr->length; vaddr += VM_PAGE_SIZE) {
980433d6423SLionel Sambuc 			orig_ph = physblock_get(vr, vaddr);
981433d6423SLionel Sambuc 			new_ph = physblock_get(newvr, vaddr);
982433d6423SLionel Sambuc 			if(!orig_ph) { assert(!new_ph); continue;}
983433d6423SLionel Sambuc 			assert(new_ph);
984433d6423SLionel Sambuc 			assert(orig_ph != new_ph);
985433d6423SLionel Sambuc 			assert(orig_ph->ph == new_ph->ph);
986433d6423SLionel Sambuc 		}
987433d6423SLionel Sambuc 	}
988433d6423SLionel Sambuc #endif
98963483e02SCristiano Giuffrida 		if(vr == end_src_vr) {
99063483e02SCristiano Giuffrida 			break;
99163483e02SCristiano Giuffrida 		}
992433d6423SLionel Sambuc 		region_incr_iter(&v_iter);
993433d6423SLionel Sambuc 	}
994433d6423SLionel Sambuc 
995433d6423SLionel Sambuc 	map_writept(src);
996433d6423SLionel Sambuc 	map_writept(dst);
997433d6423SLionel Sambuc 
998433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
999433d6423SLionel Sambuc 	return OK;
1000433d6423SLionel Sambuc }
1001433d6423SLionel Sambuc 
map_region_extend_upto_v(struct vmproc * vmp,vir_bytes v)1002433d6423SLionel Sambuc int map_region_extend_upto_v(struct vmproc *vmp, vir_bytes v)
1003433d6423SLionel Sambuc {
1004433d6423SLionel Sambuc 	vir_bytes offset = v, limit, extralen;
1005433d6423SLionel Sambuc 	struct vir_region *vr, *nextvr;
1006433d6423SLionel Sambuc 	struct phys_region **newpr;
1007433d6423SLionel Sambuc 	int newslots, prevslots, addedslots, r;
1008433d6423SLionel Sambuc 
1009433d6423SLionel Sambuc 	offset = roundup(offset, VM_PAGE_SIZE);
1010433d6423SLionel Sambuc 
1011433d6423SLionel Sambuc 	if(!(vr = region_search(&vmp->vm_regions_avl, offset, AVL_LESS))) {
1012433d6423SLionel Sambuc 		printf("VM: nothing to extend\n");
1013433d6423SLionel Sambuc 		return ENOMEM;
1014433d6423SLionel Sambuc 	}
1015433d6423SLionel Sambuc 
1016433d6423SLionel Sambuc 	if(vr->vaddr + vr->length >= v) return OK;
1017433d6423SLionel Sambuc 
1018433d6423SLionel Sambuc 	limit = vr->vaddr + vr->length;
1019433d6423SLionel Sambuc 
1020433d6423SLionel Sambuc 	assert(vr->vaddr <= offset);
1021433d6423SLionel Sambuc 	newslots = phys_slot(offset - vr->vaddr);
1022433d6423SLionel Sambuc 	prevslots = phys_slot(vr->length);
1023433d6423SLionel Sambuc 	assert(newslots >= prevslots);
1024433d6423SLionel Sambuc 	addedslots = newslots - prevslots;
1025433d6423SLionel Sambuc 	extralen = offset - limit;
1026433d6423SLionel Sambuc 	assert(extralen > 0);
1027433d6423SLionel Sambuc 
1028433d6423SLionel Sambuc 	if((nextvr = getnextvr(vr))) {
1029433d6423SLionel Sambuc 		assert(offset <= nextvr->vaddr);
1030433d6423SLionel Sambuc 	}
1031433d6423SLionel Sambuc 
1032433d6423SLionel Sambuc 	if(nextvr && nextvr->vaddr < offset) {
1033433d6423SLionel Sambuc 		printf("VM: can't grow into next region\n");
1034433d6423SLionel Sambuc 		return ENOMEM;
1035433d6423SLionel Sambuc 	}
1036433d6423SLionel Sambuc 
1037433d6423SLionel Sambuc 	if(!vr->def_memtype->ev_resize) {
1038433d6423SLionel Sambuc 		if(!map_page_region(vmp, limit, 0, extralen,
1039433d6423SLionel Sambuc 			VR_WRITABLE | VR_ANON,
1040433d6423SLionel Sambuc 			0, &mem_type_anon)) {
1041433d6423SLionel Sambuc 			printf("resize: couldn't put anon memory there\n");
1042433d6423SLionel Sambuc 			return ENOMEM;
1043433d6423SLionel Sambuc 		}
1044433d6423SLionel Sambuc 		return OK;
1045433d6423SLionel Sambuc 	}
1046433d6423SLionel Sambuc 
1047433d6423SLionel Sambuc 	if(!(newpr = realloc(vr->physblocks,
1048433d6423SLionel Sambuc 		newslots * sizeof(struct phys_region *)))) {
1049433d6423SLionel Sambuc 		printf("VM: map_region_extend_upto_v: realloc failed\n");
1050433d6423SLionel Sambuc 		return ENOMEM;
1051433d6423SLionel Sambuc 	}
1052433d6423SLionel Sambuc 
1053433d6423SLionel Sambuc 	vr->physblocks = newpr;
1054433d6423SLionel Sambuc 	memset(vr->physblocks + prevslots, 0,
1055433d6423SLionel Sambuc 		addedslots * sizeof(struct phys_region *));
1056433d6423SLionel Sambuc 
1057433d6423SLionel Sambuc 	r = vr->def_memtype->ev_resize(vmp, vr, offset - vr->vaddr);
1058433d6423SLionel Sambuc 
1059433d6423SLionel Sambuc 	return r;
1060433d6423SLionel Sambuc }
1061433d6423SLionel Sambuc 
1062433d6423SLionel Sambuc /*========================================================================*
1063433d6423SLionel Sambuc  *				map_unmap_region	     	  	*
1064433d6423SLionel Sambuc  *========================================================================*/
map_unmap_region(struct vmproc * vmp,struct vir_region * r,vir_bytes offset,vir_bytes len)1065433d6423SLionel Sambuc int map_unmap_region(struct vmproc *vmp, struct vir_region *r,
1066433d6423SLionel Sambuc 	vir_bytes offset, vir_bytes len)
1067433d6423SLionel Sambuc {
1068433d6423SLionel Sambuc /* Shrink the region by 'len' bytes, from the start. Unreference
1069433d6423SLionel Sambuc  * memory it used to reference if any.
1070433d6423SLionel Sambuc  */
1071433d6423SLionel Sambuc 	vir_bytes regionstart;
1072433d6423SLionel Sambuc 	int freeslots = phys_slot(len);
1073433d6423SLionel Sambuc 
1074433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
1075433d6423SLionel Sambuc 
1076433d6423SLionel Sambuc 	if(offset+len > r->length || (len % VM_PAGE_SIZE)) {
1077433d6423SLionel Sambuc 		printf("VM: bogus length 0x%lx\n", len);
1078433d6423SLionel Sambuc 		return EINVAL;
1079433d6423SLionel Sambuc 	}
1080433d6423SLionel Sambuc 
1081433d6423SLionel Sambuc 	regionstart = r->vaddr + offset;
1082433d6423SLionel Sambuc 
1083433d6423SLionel Sambuc 	/* unreference its memory */
1084433d6423SLionel Sambuc 	map_subfree(r, offset, len);
1085433d6423SLionel Sambuc 
1086433d6423SLionel Sambuc 	/* if unmap was at start/end of this region, it actually shrinks */
1087433d6423SLionel Sambuc 	if(r->length == len) {
1088433d6423SLionel Sambuc 		/* Whole region disappears. Unlink and free it. */
1089433d6423SLionel Sambuc 		region_remove(&vmp->vm_regions_avl, r->vaddr);
1090433d6423SLionel Sambuc 		map_free(r);
1091433d6423SLionel Sambuc 	} else if(offset == 0) {
1092433d6423SLionel Sambuc 		struct phys_region *pr;
1093433d6423SLionel Sambuc 		vir_bytes voffset;
1094433d6423SLionel Sambuc 		int remslots;
1095433d6423SLionel Sambuc 
1096433d6423SLionel Sambuc 		if(!r->def_memtype->ev_lowshrink) {
1097433d6423SLionel Sambuc 			printf("VM: low-shrinking not implemented for %s\n",
1098433d6423SLionel Sambuc 				r->def_memtype->name);
1099433d6423SLionel Sambuc 			return EINVAL;
1100433d6423SLionel Sambuc 		}
1101433d6423SLionel Sambuc 
1102433d6423SLionel Sambuc 		if(r->def_memtype->ev_lowshrink(r, len) != OK) {
1103433d6423SLionel Sambuc 			printf("VM: low-shrinking failed for %s\n",
1104433d6423SLionel Sambuc 				r->def_memtype->name);
1105433d6423SLionel Sambuc 			return EINVAL;
1106433d6423SLionel Sambuc 		}
1107433d6423SLionel Sambuc 
1108433d6423SLionel Sambuc 		region_remove(&vmp->vm_regions_avl, r->vaddr);
1109433d6423SLionel Sambuc 
1110433d6423SLionel Sambuc 		USE(r,
1111433d6423SLionel Sambuc 		r->vaddr += len;);
1112433d6423SLionel Sambuc 
1113433d6423SLionel Sambuc 		remslots = phys_slot(r->length);
1114433d6423SLionel Sambuc 
1115433d6423SLionel Sambuc 		region_insert(&vmp->vm_regions_avl, r);
1116433d6423SLionel Sambuc 
1117433d6423SLionel Sambuc 		/* vaddr has increased; to make all the phys_regions
1118433d6423SLionel Sambuc 		 * point to the same addresses, make them shrink by the
1119433d6423SLionel Sambuc 		 * same amount.
1120433d6423SLionel Sambuc 		 */
1121433d6423SLionel Sambuc 		for(voffset = len; voffset < r->length;
1122433d6423SLionel Sambuc 			voffset += VM_PAGE_SIZE) {
1123433d6423SLionel Sambuc 			if(!(pr = physblock_get(r, voffset))) continue;
1124433d6423SLionel Sambuc 			assert(pr->offset >= offset);
1125433d6423SLionel Sambuc 			assert(pr->offset >= len);
1126433d6423SLionel Sambuc 			USE(pr, pr->offset -= len;);
1127433d6423SLionel Sambuc 		}
1128433d6423SLionel Sambuc 		if(remslots)
1129433d6423SLionel Sambuc 			memmove(r->physblocks, r->physblocks + freeslots,
1130433d6423SLionel Sambuc 				remslots * sizeof(struct phys_region *));
1131433d6423SLionel Sambuc 		USE(r, r->length -= len;);
1132433d6423SLionel Sambuc 	} else if(offset + len == r->length) {
1133433d6423SLionel Sambuc 		assert(len <= r->length);
1134433d6423SLionel Sambuc 		r->length -= len;
1135433d6423SLionel Sambuc 	}
1136433d6423SLionel Sambuc 
1137433d6423SLionel Sambuc 	SANITYCHECK(SCL_DETAIL);
1138433d6423SLionel Sambuc 
1139433d6423SLionel Sambuc 	if(pt_writemap(vmp, &vmp->vm_pt, regionstart,
1140433d6423SLionel Sambuc 	  MAP_NONE, len, 0, WMF_OVERWRITE) != OK) {
1141433d6423SLionel Sambuc 	    printf("VM: map_unmap_region: pt_writemap failed\n");
1142433d6423SLionel Sambuc 	    return ENOMEM;
1143433d6423SLionel Sambuc 	}
1144433d6423SLionel Sambuc 
1145433d6423SLionel Sambuc 	SANITYCHECK(SCL_FUNCTIONS);
1146433d6423SLionel Sambuc 
1147433d6423SLionel Sambuc 	return OK;
1148433d6423SLionel Sambuc }
1149433d6423SLionel Sambuc 
split_region(struct vmproc * vmp,struct vir_region * vr,struct vir_region ** vr1,struct vir_region ** vr2,vir_bytes split_len)1150433d6423SLionel Sambuc static int split_region(struct vmproc *vmp, struct vir_region *vr,
1151433d6423SLionel Sambuc 	struct vir_region **vr1, struct vir_region **vr2, vir_bytes split_len)
1152433d6423SLionel Sambuc {
1153433d6423SLionel Sambuc 	struct vir_region *r1 = NULL, *r2 = NULL;
1154433d6423SLionel Sambuc 	vir_bytes rem_len = vr->length - split_len;
1155433d6423SLionel Sambuc 	int slots1, slots2;
1156433d6423SLionel Sambuc 	vir_bytes voffset;
1157433d6423SLionel Sambuc 	int n1 = 0, n2 = 0;
1158433d6423SLionel Sambuc 
1159433d6423SLionel Sambuc 	assert(!(split_len % VM_PAGE_SIZE));
1160433d6423SLionel Sambuc 	assert(!(rem_len % VM_PAGE_SIZE));
1161433d6423SLionel Sambuc 	assert(!(vr->vaddr % VM_PAGE_SIZE));
1162433d6423SLionel Sambuc 	assert(!(vr->length % VM_PAGE_SIZE));
1163433d6423SLionel Sambuc 
1164433d6423SLionel Sambuc 	if(!vr->def_memtype->ev_split) {
1165433d6423SLionel Sambuc 		printf("VM: split region not implemented for %s\n",
1166433d6423SLionel Sambuc 			vr->def_memtype->name);
116748e74378SBen Gras 		sys_diagctl_stacktrace(vmp->vm_endpoint);
1168433d6423SLionel Sambuc 		return EINVAL;
1169433d6423SLionel Sambuc 	}
1170433d6423SLionel Sambuc 
1171433d6423SLionel Sambuc 	slots1 = phys_slot(split_len);
1172433d6423SLionel Sambuc 	slots2 = phys_slot(rem_len);
1173433d6423SLionel Sambuc 
1174433d6423SLionel Sambuc 	if(!(r1 = region_new(vmp, vr->vaddr, split_len, vr->flags,
1175433d6423SLionel Sambuc 		vr->def_memtype))) {
1176433d6423SLionel Sambuc 		goto bail;
1177433d6423SLionel Sambuc 	}
1178433d6423SLionel Sambuc 
1179433d6423SLionel Sambuc 	if(!(r2 = region_new(vmp, vr->vaddr+split_len, rem_len, vr->flags,
1180433d6423SLionel Sambuc 		vr->def_memtype))) {
1181433d6423SLionel Sambuc 		map_free(r1);
1182433d6423SLionel Sambuc 		goto bail;
1183433d6423SLionel Sambuc 	}
1184433d6423SLionel Sambuc 
1185433d6423SLionel Sambuc 	for(voffset = 0; voffset < r1->length; voffset += VM_PAGE_SIZE) {
1186433d6423SLionel Sambuc 		struct phys_region *ph, *phn;
1187433d6423SLionel Sambuc 		if(!(ph = physblock_get(vr, voffset))) continue;
1188433d6423SLionel Sambuc 		if(!(phn = pb_reference(ph->ph, voffset, r1, ph->memtype)))
1189433d6423SLionel Sambuc 			goto bail;
1190433d6423SLionel Sambuc 		n1++;
1191433d6423SLionel Sambuc 	}
1192433d6423SLionel Sambuc 
1193433d6423SLionel Sambuc 	for(voffset = 0; voffset < r2->length; voffset += VM_PAGE_SIZE) {
1194433d6423SLionel Sambuc 		struct phys_region *ph, *phn;
1195433d6423SLionel Sambuc 		if(!(ph = physblock_get(vr, split_len + voffset))) continue;
1196433d6423SLionel Sambuc 		if(!(phn = pb_reference(ph->ph, voffset, r2, ph->memtype)))
1197433d6423SLionel Sambuc 			goto bail;
1198433d6423SLionel Sambuc 		n2++;
1199433d6423SLionel Sambuc 	}
1200433d6423SLionel Sambuc 
1201433d6423SLionel Sambuc 	vr->def_memtype->ev_split(vmp, vr, r1, r2);
1202433d6423SLionel Sambuc 
1203433d6423SLionel Sambuc 	region_remove(&vmp->vm_regions_avl, vr->vaddr);
1204433d6423SLionel Sambuc 	map_free(vr);
1205433d6423SLionel Sambuc 	region_insert(&vmp->vm_regions_avl, r1);
1206433d6423SLionel Sambuc 	region_insert(&vmp->vm_regions_avl, r2);
1207433d6423SLionel Sambuc 
1208433d6423SLionel Sambuc 	*vr1 = r1;
1209433d6423SLionel Sambuc 	*vr2 = r2;
1210433d6423SLionel Sambuc 
1211433d6423SLionel Sambuc 	return OK;
1212433d6423SLionel Sambuc 
1213433d6423SLionel Sambuc   bail:
1214433d6423SLionel Sambuc 	if(r1) map_free(r1);
1215433d6423SLionel Sambuc 	if(r2) map_free(r2);
1216433d6423SLionel Sambuc 
1217433d6423SLionel Sambuc 	printf("split_region: failed\n");
1218433d6423SLionel Sambuc 
1219433d6423SLionel Sambuc 	return ENOMEM;
1220433d6423SLionel Sambuc }
1221433d6423SLionel Sambuc 
map_unmap_range(struct vmproc * vmp,vir_bytes unmap_start,vir_bytes length)1222433d6423SLionel Sambuc int map_unmap_range(struct vmproc *vmp, vir_bytes unmap_start, vir_bytes length)
1223433d6423SLionel Sambuc {
1224433d6423SLionel Sambuc 	vir_bytes o = unmap_start % VM_PAGE_SIZE, unmap_limit;
1225433d6423SLionel Sambuc 	region_iter v_iter;
1226433d6423SLionel Sambuc 	struct vir_region *vr, *nextvr;
1227433d6423SLionel Sambuc 
1228433d6423SLionel Sambuc 	unmap_start -= o;
1229433d6423SLionel Sambuc 	length += o;
1230433d6423SLionel Sambuc 	length = roundup(length, VM_PAGE_SIZE);
1231433d6423SLionel Sambuc 	unmap_limit = length + unmap_start;
1232433d6423SLionel Sambuc 
1233433d6423SLionel Sambuc 	if(length < VM_PAGE_SIZE) return EINVAL;
1234433d6423SLionel Sambuc 	if(unmap_limit <= unmap_start) return EINVAL;
1235433d6423SLionel Sambuc 
1236433d6423SLionel Sambuc 	region_start_iter(&vmp->vm_regions_avl, &v_iter, unmap_start, AVL_LESS_EQUAL);
1237433d6423SLionel Sambuc 
1238433d6423SLionel Sambuc 	if(!(vr = region_get_iter(&v_iter))) {
1239433d6423SLionel Sambuc 		region_start_iter(&vmp->vm_regions_avl, &v_iter, unmap_start, AVL_GREATER);
1240433d6423SLionel Sambuc 		if(!(vr = region_get_iter(&v_iter))) {
1241433d6423SLionel Sambuc 			return OK;
1242433d6423SLionel Sambuc 		}
1243433d6423SLionel Sambuc 	}
1244433d6423SLionel Sambuc 
1245433d6423SLionel Sambuc 	assert(vr);
1246433d6423SLionel Sambuc 
1247433d6423SLionel Sambuc 	for(; vr && vr->vaddr < unmap_limit; vr = nextvr) {
1248433d6423SLionel Sambuc 		vir_bytes thislimit = vr->vaddr + vr->length;
1249433d6423SLionel Sambuc 		vir_bytes this_unmap_start, this_unmap_limit;
1250433d6423SLionel Sambuc 		vir_bytes remainlen;
1251433d6423SLionel Sambuc 		int r;
1252433d6423SLionel Sambuc 
1253433d6423SLionel Sambuc 		region_incr_iter(&v_iter);
1254433d6423SLionel Sambuc 		nextvr = region_get_iter(&v_iter);
1255433d6423SLionel Sambuc 
1256433d6423SLionel Sambuc 		assert(thislimit > vr->vaddr);
1257433d6423SLionel Sambuc 
1258433d6423SLionel Sambuc 		this_unmap_start = MAX(unmap_start, vr->vaddr);
1259433d6423SLionel Sambuc 		this_unmap_limit = MIN(unmap_limit, thislimit);
1260433d6423SLionel Sambuc 
1261433d6423SLionel Sambuc 		if(this_unmap_start >= this_unmap_limit) continue;
1262433d6423SLionel Sambuc 
1263433d6423SLionel Sambuc 		if(this_unmap_start > vr->vaddr && this_unmap_limit < thislimit) {
1264433d6423SLionel Sambuc 			struct vir_region *vr1, *vr2;
1265433d6423SLionel Sambuc 			vir_bytes split_len = this_unmap_limit - vr->vaddr;
1266433d6423SLionel Sambuc 			assert(split_len > 0);
1267433d6423SLionel Sambuc 			assert(split_len < vr->length);
1268433d6423SLionel Sambuc 			if((r=split_region(vmp, vr, &vr1, &vr2, split_len)) != OK) {
1269433d6423SLionel Sambuc 				printf("VM: unmap split failed\n");
1270433d6423SLionel Sambuc 				return r;
1271433d6423SLionel Sambuc 			}
1272433d6423SLionel Sambuc 			vr = vr1;
1273433d6423SLionel Sambuc 			thislimit = vr->vaddr + vr->length;
1274433d6423SLionel Sambuc 		}
1275433d6423SLionel Sambuc 
1276433d6423SLionel Sambuc 		remainlen = this_unmap_limit - vr->vaddr;
1277433d6423SLionel Sambuc 
1278433d6423SLionel Sambuc 		assert(this_unmap_start >= vr->vaddr);
1279433d6423SLionel Sambuc 		assert(this_unmap_limit <= thislimit);
1280433d6423SLionel Sambuc 		assert(remainlen > 0);
1281433d6423SLionel Sambuc 
1282433d6423SLionel Sambuc 		r = map_unmap_region(vmp, vr, this_unmap_start - vr->vaddr,
1283433d6423SLionel Sambuc 			this_unmap_limit - this_unmap_start);
1284433d6423SLionel Sambuc 
1285433d6423SLionel Sambuc 		if(r != OK) {
1286433d6423SLionel Sambuc 			printf("map_unmap_range: map_unmap_region failed\n");
1287433d6423SLionel Sambuc 			return r;
1288433d6423SLionel Sambuc 		}
1289433d6423SLionel Sambuc 
1290f53651deSBen Gras 		if(nextvr) {
1291433d6423SLionel Sambuc 			region_start_iter(&vmp->vm_regions_avl, &v_iter, nextvr->vaddr, AVL_EQUAL);
1292433d6423SLionel Sambuc 			assert(region_get_iter(&v_iter) == nextvr);
1293433d6423SLionel Sambuc 		}
1294f53651deSBen Gras 	}
1295433d6423SLionel Sambuc 
1296433d6423SLionel Sambuc 	return OK;
1297433d6423SLionel Sambuc 
1298433d6423SLionel Sambuc }
1299433d6423SLionel Sambuc 
1300433d6423SLionel Sambuc /*========================================================================*
130163483e02SCristiano Giuffrida  *			  map_region_lookup_type			  *
130263483e02SCristiano Giuffrida  *========================================================================*/
map_region_lookup_type(struct vmproc * vmp,u32_t type)130363483e02SCristiano Giuffrida struct vir_region* map_region_lookup_type(struct vmproc *vmp, u32_t type)
130463483e02SCristiano Giuffrida {
130563483e02SCristiano Giuffrida 	struct vir_region *vr;
130663483e02SCristiano Giuffrida 	struct phys_region *pr;
130763483e02SCristiano Giuffrida 	vir_bytes used = 0, weighted = 0;
130863483e02SCristiano Giuffrida 	region_iter v_iter;
130963483e02SCristiano Giuffrida 	region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
131063483e02SCristiano Giuffrida 
131163483e02SCristiano Giuffrida 	while((vr = region_get_iter(&v_iter))) {
131263483e02SCristiano Giuffrida 		region_incr_iter(&v_iter);
131363483e02SCristiano Giuffrida 		if(vr->flags & type)
131463483e02SCristiano Giuffrida 			return vr;
131563483e02SCristiano Giuffrida 	}
131663483e02SCristiano Giuffrida 
131763483e02SCristiano Giuffrida 	return NULL;
131863483e02SCristiano Giuffrida }
131963483e02SCristiano Giuffrida 
132063483e02SCristiano Giuffrida /*========================================================================*
1321433d6423SLionel Sambuc  *				map_get_phys				  *
1322433d6423SLionel Sambuc  *========================================================================*/
map_get_phys(struct vmproc * vmp,vir_bytes addr,phys_bytes * r)1323433d6423SLionel Sambuc int map_get_phys(struct vmproc *vmp, vir_bytes addr, phys_bytes *r)
1324433d6423SLionel Sambuc {
1325433d6423SLionel Sambuc 	struct vir_region *vr;
1326433d6423SLionel Sambuc 
1327433d6423SLionel Sambuc 	if (!(vr = map_lookup(vmp, addr, NULL)) ||
1328433d6423SLionel Sambuc 		(vr->vaddr != addr))
1329433d6423SLionel Sambuc 		return EINVAL;
1330433d6423SLionel Sambuc 
1331433d6423SLionel Sambuc 	if (!vr->def_memtype->regionid)
1332433d6423SLionel Sambuc 		return EINVAL;
1333433d6423SLionel Sambuc 
1334433d6423SLionel Sambuc 	if(r)
1335433d6423SLionel Sambuc 		*r = vr->def_memtype->regionid(vr);
1336433d6423SLionel Sambuc 
1337433d6423SLionel Sambuc 	return OK;
1338433d6423SLionel Sambuc }
1339433d6423SLionel Sambuc 
1340433d6423SLionel Sambuc /*========================================================================*
1341433d6423SLionel Sambuc  *				map_get_ref				  *
1342433d6423SLionel Sambuc  *========================================================================*/
map_get_ref(struct vmproc * vmp,vir_bytes addr,u8_t * cnt)1343433d6423SLionel Sambuc int map_get_ref(struct vmproc *vmp, vir_bytes addr, u8_t *cnt)
1344433d6423SLionel Sambuc {
1345433d6423SLionel Sambuc 	struct vir_region *vr;
1346433d6423SLionel Sambuc 
1347433d6423SLionel Sambuc 	if (!(vr = map_lookup(vmp, addr, NULL)) ||
1348433d6423SLionel Sambuc 		(vr->vaddr != addr) || !vr->def_memtype->refcount)
1349433d6423SLionel Sambuc 		return EINVAL;
1350433d6423SLionel Sambuc 
1351433d6423SLionel Sambuc 	if (cnt)
1352433d6423SLionel Sambuc 		*cnt = vr->def_memtype->refcount(vr);
1353433d6423SLionel Sambuc 
1354433d6423SLionel Sambuc 	return OK;
1355433d6423SLionel Sambuc }
1356433d6423SLionel Sambuc 
get_usage_info_kernel(struct vm_usage_info * vui)1357433d6423SLionel Sambuc void get_usage_info_kernel(struct vm_usage_info *vui)
1358433d6423SLionel Sambuc {
1359433d6423SLionel Sambuc 	memset(vui, 0, sizeof(*vui));
1360433d6423SLionel Sambuc 	vui->vui_total = kernel_boot_info.kernel_allocated_bytes +
1361433d6423SLionel Sambuc 		kernel_boot_info.kernel_allocated_bytes_dynamic;
13628b30ac4cSDavid van Moolenbroek 	/* All of the kernel's pages are actually mapped in. */
13638b30ac4cSDavid van Moolenbroek 	vui->vui_virtual = vui->vui_mvirtual = vui->vui_total;
1364433d6423SLionel Sambuc }
1365433d6423SLionel Sambuc 
get_usage_info_vm(struct vm_usage_info * vui)1366433d6423SLionel Sambuc static void get_usage_info_vm(struct vm_usage_info *vui)
1367433d6423SLionel Sambuc {
1368433d6423SLionel Sambuc 	memset(vui, 0, sizeof(*vui));
1369433d6423SLionel Sambuc 	vui->vui_total = kernel_boot_info.vm_allocated_bytes +
1370433d6423SLionel Sambuc 		get_vm_self_pages() * VM_PAGE_SIZE;
13718b30ac4cSDavid van Moolenbroek 	/* All of VM's pages are actually mapped in. */
13728b30ac4cSDavid van Moolenbroek 	vui->vui_virtual = vui->vui_mvirtual = vui->vui_total;
13738b30ac4cSDavid van Moolenbroek }
13748b30ac4cSDavid van Moolenbroek 
13758b30ac4cSDavid van Moolenbroek /*
13768b30ac4cSDavid van Moolenbroek  * Return whether the given region is for the associated process's stack.
13778b30ac4cSDavid van Moolenbroek  * Unfortunately, we do not actually have this information: in most cases, VM
13788b30ac4cSDavid van Moolenbroek  * is not responsible for actually setting up the stack in the first place.
13798b30ac4cSDavid van Moolenbroek  * Fortunately, this is only for statistical purposes, so we can get away with
13808b30ac4cSDavid van Moolenbroek  * guess work.  However, it is certainly not accurate in the light of userspace
13818b30ac4cSDavid van Moolenbroek  * thread stacks, or if the process is messing with its stack in any way, or if
13828b30ac4cSDavid van Moolenbroek  * (currently) VFS decides to put the stack elsewhere, etcetera.
13838b30ac4cSDavid van Moolenbroek  */
13848b30ac4cSDavid van Moolenbroek static int
is_stack_region(struct vir_region * vr)13858b30ac4cSDavid van Moolenbroek is_stack_region(struct vir_region * vr)
13868b30ac4cSDavid van Moolenbroek {
13878b30ac4cSDavid van Moolenbroek 
13888b30ac4cSDavid van Moolenbroek 	return (vr->vaddr == VM_STACKTOP - DEFAULT_STACK_LIMIT &&
13898b30ac4cSDavid van Moolenbroek 	    vr->length == DEFAULT_STACK_LIMIT);
1390433d6423SLionel Sambuc }
1391433d6423SLionel Sambuc 
1392433d6423SLionel Sambuc /*========================================================================*
1393433d6423SLionel Sambuc  *				get_usage_info				  *
1394433d6423SLionel Sambuc  *========================================================================*/
get_usage_info(struct vmproc * vmp,struct vm_usage_info * vui)1395433d6423SLionel Sambuc void get_usage_info(struct vmproc *vmp, struct vm_usage_info *vui)
1396433d6423SLionel Sambuc {
1397433d6423SLionel Sambuc 	struct vir_region *vr;
1398433d6423SLionel Sambuc 	struct phys_region *ph;
1399433d6423SLionel Sambuc 	region_iter v_iter;
1400433d6423SLionel Sambuc 	region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
1401433d6423SLionel Sambuc 	vir_bytes voffset;
1402433d6423SLionel Sambuc 
1403433d6423SLionel Sambuc 	memset(vui, 0, sizeof(*vui));
1404433d6423SLionel Sambuc 
1405433d6423SLionel Sambuc 	if(vmp->vm_endpoint == VM_PROC_NR) {
1406433d6423SLionel Sambuc 		get_usage_info_vm(vui);
1407433d6423SLionel Sambuc 		return;
1408433d6423SLionel Sambuc 	}
1409433d6423SLionel Sambuc 
1410433d6423SLionel Sambuc 	if(vmp->vm_endpoint < 0) {
1411433d6423SLionel Sambuc 		get_usage_info_kernel(vui);
1412433d6423SLionel Sambuc 		return;
1413433d6423SLionel Sambuc 	}
1414433d6423SLionel Sambuc 
1415433d6423SLionel Sambuc 	while((vr = region_get_iter(&v_iter))) {
14168b30ac4cSDavid van Moolenbroek 		vui->vui_virtual += vr->length;
14178b30ac4cSDavid van Moolenbroek 		vui->vui_mvirtual += vr->length;
1418433d6423SLionel Sambuc 		for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) {
14198b30ac4cSDavid van Moolenbroek 			if(!(ph = physblock_get(vr, voffset))) {
14208b30ac4cSDavid van Moolenbroek 				/* mvirtual: discount unmapped stack pages. */
14218b30ac4cSDavid van Moolenbroek 				if (is_stack_region(vr))
14228b30ac4cSDavid van Moolenbroek 					vui->vui_mvirtual -= VM_PAGE_SIZE;
14238b30ac4cSDavid van Moolenbroek 				continue;
14248b30ac4cSDavid van Moolenbroek 			}
1425433d6423SLionel Sambuc 			/* All present pages are counted towards the total. */
1426433d6423SLionel Sambuc 			vui->vui_total += VM_PAGE_SIZE;
1427433d6423SLionel Sambuc 
1428433d6423SLionel Sambuc 			if (ph->ph->refcount > 1) {
1429433d6423SLionel Sambuc 				/* Any page with a refcount > 1 is common. */
1430433d6423SLionel Sambuc 				vui->vui_common += VM_PAGE_SIZE;
1431433d6423SLionel Sambuc 
1432433d6423SLionel Sambuc 				/* Any common, non-COW page is shared. */
1433433d6423SLionel Sambuc 				if (vr->flags & VR_SHARED)
1434433d6423SLionel Sambuc 					vui->vui_shared += VM_PAGE_SIZE;
1435433d6423SLionel Sambuc 			}
1436433d6423SLionel Sambuc 		}
1437433d6423SLionel Sambuc 		region_incr_iter(&v_iter);
1438433d6423SLionel Sambuc 	}
1439*89926a4cSDavid van Moolenbroek 
1440*89926a4cSDavid van Moolenbroek 	/*
1441*89926a4cSDavid van Moolenbroek 	 * Also include getrusage resource information, so that the MIB service
1442*89926a4cSDavid van Moolenbroek 	 * need not make more than one call to VM for each process entry.
1443*89926a4cSDavid van Moolenbroek 	 */
1444*89926a4cSDavid van Moolenbroek 	vui->vui_maxrss = vmp->vm_total_max / 1024L;
1445*89926a4cSDavid van Moolenbroek 	vui->vui_minflt = vmp->vm_minor_page_fault;
1446*89926a4cSDavid van Moolenbroek 	vui->vui_majflt = vmp->vm_major_page_fault;
1447433d6423SLionel Sambuc }
1448433d6423SLionel Sambuc 
1449433d6423SLionel Sambuc /*===========================================================================*
1450433d6423SLionel Sambuc  *				get_region_info				     *
1451433d6423SLionel Sambuc  *===========================================================================*/
get_region_info(struct vmproc * vmp,struct vm_region_info * vri,int max,vir_bytes * nextp)1452433d6423SLionel Sambuc int get_region_info(struct vmproc *vmp, struct vm_region_info *vri,
1453433d6423SLionel Sambuc 	int max, vir_bytes *nextp)
1454433d6423SLionel Sambuc {
1455433d6423SLionel Sambuc 	struct vir_region *vr;
1456433d6423SLionel Sambuc 	vir_bytes next;
1457433d6423SLionel Sambuc 	int count;
1458433d6423SLionel Sambuc 	region_iter v_iter;
1459433d6423SLionel Sambuc 
1460433d6423SLionel Sambuc 	next = *nextp;
1461433d6423SLionel Sambuc 
1462433d6423SLionel Sambuc 	if (!max) return 0;
1463433d6423SLionel Sambuc 
1464433d6423SLionel Sambuc 	region_start_iter(&vmp->vm_regions_avl, &v_iter, next, AVL_GREATER_EQUAL);
1465433d6423SLionel Sambuc 	if(!(vr = region_get_iter(&v_iter))) return 0;
1466433d6423SLionel Sambuc 
1467433d6423SLionel Sambuc 	for(count = 0; (vr = region_get_iter(&v_iter)) && count < max;
1468433d6423SLionel Sambuc 	   region_incr_iter(&v_iter)) {
1469433d6423SLionel Sambuc 		struct phys_region *ph1 = NULL, *ph2 = NULL;
1470433d6423SLionel Sambuc 		vir_bytes voffset;
1471433d6423SLionel Sambuc 
1472433d6423SLionel Sambuc 		/* where to start on next iteration, regardless of what we find now */
1473433d6423SLionel Sambuc 		next = vr->vaddr + vr->length;
1474433d6423SLionel Sambuc 
1475433d6423SLionel Sambuc 		/* Report part of the region that's actually in use. */
1476433d6423SLionel Sambuc 
1477433d6423SLionel Sambuc 		/* Get first and last phys_regions, if any */
1478433d6423SLionel Sambuc 		for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) {
1479433d6423SLionel Sambuc 			struct phys_region *ph;
1480433d6423SLionel Sambuc 			if(!(ph = physblock_get(vr, voffset))) continue;
1481433d6423SLionel Sambuc 			if(!ph1) ph1 = ph;
1482433d6423SLionel Sambuc 			ph2 = ph;
1483433d6423SLionel Sambuc 		}
1484433d6423SLionel Sambuc 
1485433d6423SLionel Sambuc 		if(!ph1 || !ph2) {
1486433d6423SLionel Sambuc 			printf("skipping empty region 0x%lx-0x%lx\n",
1487433d6423SLionel Sambuc 				vr->vaddr, vr->vaddr+vr->length);
1488433d6423SLionel Sambuc 			continue;
1489433d6423SLionel Sambuc 		}
1490433d6423SLionel Sambuc 
1491433d6423SLionel Sambuc 		/* Report start+length of region starting from lowest use. */
1492433d6423SLionel Sambuc 		vri->vri_addr = vr->vaddr + ph1->offset;
1493433d6423SLionel Sambuc 		vri->vri_prot = PROT_READ;
1494433d6423SLionel Sambuc 		vri->vri_length = ph2->offset + VM_PAGE_SIZE - ph1->offset;
1495433d6423SLionel Sambuc 
1496433d6423SLionel Sambuc 		/* "AND" the provided protection with per-page protection. */
1497433d6423SLionel Sambuc 		if (vr->flags & VR_WRITABLE)
1498433d6423SLionel Sambuc 			vri->vri_prot |= PROT_WRITE;
1499433d6423SLionel Sambuc 		count++;
1500433d6423SLionel Sambuc 		vri++;
1501433d6423SLionel Sambuc 	}
1502433d6423SLionel Sambuc 
1503433d6423SLionel Sambuc 	*nextp = next;
1504433d6423SLionel Sambuc 	return count;
1505433d6423SLionel Sambuc }
1506433d6423SLionel Sambuc 
1507433d6423SLionel Sambuc /*========================================================================*
1508433d6423SLionel Sambuc  *				regionprintstats			  *
1509433d6423SLionel Sambuc  *========================================================================*/
printregionstats(struct vmproc * vmp)1510433d6423SLionel Sambuc void printregionstats(struct vmproc *vmp)
1511433d6423SLionel Sambuc {
1512433d6423SLionel Sambuc 	struct vir_region *vr;
1513433d6423SLionel Sambuc 	struct phys_region *pr;
1514433d6423SLionel Sambuc 	vir_bytes used = 0, weighted = 0;
1515433d6423SLionel Sambuc 	region_iter v_iter;
1516433d6423SLionel Sambuc 	region_start_iter_least(&vmp->vm_regions_avl, &v_iter);
1517433d6423SLionel Sambuc 
1518433d6423SLionel Sambuc 	while((vr = region_get_iter(&v_iter))) {
1519433d6423SLionel Sambuc 		vir_bytes voffset;
1520433d6423SLionel Sambuc 		region_incr_iter(&v_iter);
1521433d6423SLionel Sambuc 		if(vr->flags & VR_DIRECT)
1522433d6423SLionel Sambuc 			continue;
1523433d6423SLionel Sambuc 		for(voffset = 0; voffset < vr->length; voffset+=VM_PAGE_SIZE) {
1524433d6423SLionel Sambuc 			if(!(pr = physblock_get(vr, voffset))) continue;
1525433d6423SLionel Sambuc 			used += VM_PAGE_SIZE;
1526433d6423SLionel Sambuc 			weighted += VM_PAGE_SIZE / pr->ph->refcount;
1527433d6423SLionel Sambuc 		}
1528433d6423SLionel Sambuc 	}
1529433d6423SLionel Sambuc 
1530433d6423SLionel Sambuc 	printf("%6lukB  %6lukB\n", used/1024, weighted/1024);
1531433d6423SLionel Sambuc 
1532433d6423SLionel Sambuc 	return;
1533433d6423SLionel Sambuc }
1534433d6423SLionel Sambuc 
map_setparent(struct vmproc * vmp)1535433d6423SLionel Sambuc void map_setparent(struct vmproc *vmp)
1536433d6423SLionel Sambuc {
1537433d6423SLionel Sambuc 	region_iter iter;
1538433d6423SLionel Sambuc 	struct vir_region *vr;
1539433d6423SLionel Sambuc         region_start_iter_least(&vmp->vm_regions_avl, &iter);
1540433d6423SLionel Sambuc         while((vr = region_get_iter(&iter))) {
1541433d6423SLionel Sambuc                 USE(vr, vr->parent = vmp;);
1542433d6423SLionel Sambuc                 region_incr_iter(&iter);
1543433d6423SLionel Sambuc         }
1544433d6423SLionel Sambuc }
1545433d6423SLionel Sambuc 
physregions(struct vir_region * vr)1546433d6423SLionel Sambuc unsigned int physregions(struct vir_region *vr)
1547433d6423SLionel Sambuc {
1548433d6423SLionel Sambuc 	unsigned int n =  0;
1549433d6423SLionel Sambuc 	vir_bytes voffset;
1550433d6423SLionel Sambuc 	for(voffset = 0; voffset < vr->length; voffset += VM_PAGE_SIZE) {
1551433d6423SLionel Sambuc 		if(physblock_get(vr, voffset))
1552433d6423SLionel Sambuc 			n++;
1553433d6423SLionel Sambuc 	}
1554433d6423SLionel Sambuc 	return n;
1555433d6423SLionel Sambuc }
1556