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