xref: /netbsd-src/sys/rump/librump/rumpkern/vm.c (revision 274254cdae52594c1aa480a736aef78313d15c9c)
1 /*	$NetBSD: vm.c,v 1.53 2009/03/18 10:22:45 cegger Exp $	*/
2 
3 /*
4  * Copyright (c) 2007 Antti Kantee.  All Rights Reserved.
5  *
6  * Development of this software was supported by Google Summer of Code.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 /*
31  * Virtual memory emulation routines.  Contents:
32  *  + anon objects & pager
33  *  + misc support routines
34  *  + kmem
35  */
36 
37 /*
38  * XXX: we abuse pg->uanon for the virtual address of the storage
39  * for each page.  phys_addr would fit the job description better,
40  * except that it will create unnecessary lossage on some platforms
41  * due to not being a pointer type.
42  */
43 
44 #include <sys/cdefs.h>
45 __KERNEL_RCSID(0, "$NetBSD: vm.c,v 1.53 2009/03/18 10:22:45 cegger Exp $");
46 
47 #include <sys/param.h>
48 #include <sys/atomic.h>
49 #include <sys/null.h>
50 #include <sys/vnode.h>
51 #include <sys/buf.h>
52 #include <sys/kmem.h>
53 
54 #include <machine/pmap.h>
55 
56 #include <rump/rumpuser.h>
57 
58 #include <uvm/uvm.h>
59 #include <uvm/uvm_prot.h>
60 
61 #include "rump_private.h"
62 
63 static int ao_get(struct uvm_object *, voff_t, struct vm_page **,
64 	int *, int, vm_prot_t, int, int);
65 static int ao_put(struct uvm_object *, voff_t, voff_t, int);
66 
67 const struct uvm_pagerops aobj_pager = {
68 	.pgo_get = ao_get,
69 	.pgo_put = ao_put,
70 };
71 
72 kmutex_t uvm_pageqlock;
73 
74 struct uvmexp uvmexp;
75 struct uvm uvm;
76 
77 struct vmspace rump_vmspace;
78 struct vm_map rump_vmmap;
79 static struct vm_map_kernel kmem_map_store;
80 struct vm_map *kmem_map = &kmem_map_store.vmk_map;
81 const struct rb_tree_ops uvm_page_tree_ops;
82 
83 static struct vm_map_kernel kernel_map_store;
84 struct vm_map *kernel_map = &kernel_map_store.vmk_map;
85 
86 /*
87  * vm pages
88  */
89 
90 /* called with the object locked */
91 struct vm_page *
92 rumpvm_makepage(struct uvm_object *uobj, voff_t off)
93 {
94 	struct vm_page *pg;
95 
96 	pg = kmem_zalloc(sizeof(struct vm_page), KM_SLEEP);
97 	pg->offset = off;
98 	pg->uobject = uobj;
99 
100 	pg->uanon = (void *)kmem_zalloc(PAGE_SIZE, KM_SLEEP);
101 	pg->flags = PG_CLEAN|PG_BUSY|PG_FAKE;
102 
103 	TAILQ_INSERT_TAIL(&uobj->memq, pg, listq.queue);
104 
105 	return pg;
106 }
107 
108 /*
109  * Release a page.
110  *
111  * Called with the vm object locked.
112  */
113 void
114 uvm_pagefree(struct vm_page *pg)
115 {
116 	struct uvm_object *uobj = pg->uobject;
117 
118 	if (pg->flags & PG_WANTED)
119 		wakeup(pg);
120 
121 	TAILQ_REMOVE(&uobj->memq, pg, listq.queue);
122 	kmem_free((void *)pg->uanon, PAGE_SIZE);
123 	kmem_free(pg, sizeof(*pg));
124 }
125 
126 struct rumpva {
127 	vaddr_t addr;
128 	struct vm_page *pg;
129 
130 	LIST_ENTRY(rumpva) entries;
131 };
132 static LIST_HEAD(, rumpva) rvahead = LIST_HEAD_INITIALIZER(rvahead);
133 static kmutex_t rvamtx;
134 
135 void
136 rumpvm_enterva(vaddr_t addr, struct vm_page *pg)
137 {
138 	struct rumpva *rva;
139 
140 	rva = kmem_alloc(sizeof(struct rumpva), KM_SLEEP);
141 	rva->addr = addr;
142 	rva->pg = pg;
143 	mutex_enter(&rvamtx);
144 	LIST_INSERT_HEAD(&rvahead, rva, entries);
145 	mutex_exit(&rvamtx);
146 }
147 
148 void
149 rumpvm_flushva(struct uvm_object *uobj)
150 {
151 	struct rumpva *rva, *rva_next;
152 
153 	mutex_enter(&rvamtx);
154 	for (rva = LIST_FIRST(&rvahead); rva; rva = rva_next) {
155 		rva_next = LIST_NEXT(rva, entries);
156 		if (rva->pg->uobject == uobj) {
157 			LIST_REMOVE(rva, entries);
158 			uvm_page_unbusy(&rva->pg, 1);
159 			kmem_free(rva, sizeof(*rva));
160 		}
161 	}
162 	mutex_exit(&rvamtx);
163 }
164 
165 /*
166  * Anon object stuff
167  */
168 
169 static int
170 ao_get(struct uvm_object *uobj, voff_t off, struct vm_page **pgs,
171 	int *npages, int centeridx, vm_prot_t access_type,
172 	int advice, int flags)
173 {
174 	struct vm_page *pg;
175 	int i;
176 
177 	if (centeridx)
178 		panic("%s: centeridx != 0 not supported", __func__);
179 
180 	/* loop over pages */
181 	off = trunc_page(off);
182 	for (i = 0; i < *npages; i++) {
183  retrylookup:
184 		pg = uvm_pagelookup(uobj, off + (i << PAGE_SHIFT));
185 		if (pg) {
186 			if (pg->flags & PG_BUSY) {
187 				pg->flags |= PG_WANTED;
188 				UVM_UNLOCK_AND_WAIT(pg, &uobj->vmobjlock, 0,
189 				    "aogetpg", 0);
190 				goto retrylookup;
191 			}
192 			pg->flags |= PG_BUSY;
193 			pgs[i] = pg;
194 		} else {
195 			pg = rumpvm_makepage(uobj, off + (i << PAGE_SHIFT));
196 			pgs[i] = pg;
197 		}
198 	}
199 	mutex_exit(&uobj->vmobjlock);
200 
201 	return 0;
202 
203 }
204 
205 static int
206 ao_put(struct uvm_object *uobj, voff_t start, voff_t stop, int flags)
207 {
208 	struct vm_page *pg;
209 
210 	/* we only free all pages for now */
211 	if ((flags & PGO_FREE) == 0 || (flags & PGO_ALLPAGES) == 0) {
212 		mutex_exit(&uobj->vmobjlock);
213 		return 0;
214 	}
215 
216 	while ((pg = TAILQ_FIRST(&uobj->memq)) != NULL)
217 		uvm_pagefree(pg);
218 	mutex_exit(&uobj->vmobjlock);
219 
220 	return 0;
221 }
222 
223 struct uvm_object *
224 uao_create(vsize_t size, int flags)
225 {
226 	struct uvm_object *uobj;
227 
228 	uobj = kmem_zalloc(sizeof(struct uvm_object), KM_SLEEP);
229 	uobj->pgops = &aobj_pager;
230 	TAILQ_INIT(&uobj->memq);
231 	mutex_init(&uobj->vmobjlock, MUTEX_DEFAULT, IPL_NONE);
232 
233 	return uobj;
234 }
235 
236 void
237 uao_detach(struct uvm_object *uobj)
238 {
239 
240 	mutex_enter(&uobj->vmobjlock);
241 	ao_put(uobj, 0, 0, PGO_ALLPAGES | PGO_FREE);
242 	kmem_free(uobj, sizeof(*uobj));
243 }
244 
245 /*
246  * Misc routines
247  */
248 
249 static kmutex_t cachepgmtx;
250 
251 void
252 rumpvm_init(void)
253 {
254 
255 	uvmexp.free = 1024*1024; /* XXX */
256 	uvm.pagedaemon_lwp = NULL; /* doesn't match curlwp */
257 	rump_vmspace.vm_map.pmap = pmap_kernel();
258 
259 	mutex_init(&rvamtx, MUTEX_DEFAULT, 0);
260 	mutex_init(&uvm_pageqlock, MUTEX_DEFAULT, 0);
261 	mutex_init(&cachepgmtx, MUTEX_DEFAULT, 0);
262 
263 	kernel_map->pmap = pmap_kernel();
264 	callback_head_init(&kernel_map_store.vmk_reclaim_callback, IPL_VM);
265 	kmem_map->pmap = pmap_kernel();
266 	callback_head_init(&kmem_map_store.vmk_reclaim_callback, IPL_VM);
267 }
268 
269 void
270 uvm_pageactivate(struct vm_page *pg)
271 {
272 
273 	/* nada */
274 }
275 
276 void
277 uvm_pagewire(struct vm_page *pg)
278 {
279 
280 	/* nada */
281 }
282 
283 void
284 uvm_pageunwire(struct vm_page *pg)
285 {
286 
287 	/* nada */
288 }
289 
290 int
291 uvm_mmap(struct vm_map *map, vaddr_t *addr, vsize_t size, vm_prot_t prot,
292 	vm_prot_t maxprot, int flags, void *handle, voff_t off, vsize_t locklim)
293 {
294 
295 	panic("%s: unimplemented", __func__);
296 }
297 
298 vaddr_t
299 uvm_pagermapin(struct vm_page **pps, int npages, int flags)
300 {
301 
302 	panic("%s: unimplemented", __func__);
303 }
304 
305 /* Called with the vm object locked */
306 struct vm_page *
307 uvm_pagelookup(struct uvm_object *uobj, voff_t off)
308 {
309 	struct vm_page *pg;
310 
311 	TAILQ_FOREACH(pg, &uobj->memq, listq.queue) {
312 		if (pg->offset == off) {
313 			return pg;
314 		}
315 	}
316 
317 	return NULL;
318 }
319 
320 struct vm_page *
321 uvm_pageratop(vaddr_t va)
322 {
323 	struct rumpva *rva;
324 
325 	mutex_enter(&rvamtx);
326 	LIST_FOREACH(rva, &rvahead, entries)
327 		if (rva->addr == va)
328 			break;
329 	mutex_exit(&rvamtx);
330 
331 	if (rva == NULL)
332 		panic("%s: va %llu", __func__, (unsigned long long)va);
333 
334 	return rva->pg;
335 }
336 
337 void
338 uvm_page_unbusy(struct vm_page **pgs, int npgs)
339 {
340 	struct vm_page *pg;
341 	int i;
342 
343 	for (i = 0; i < npgs; i++) {
344 		pg = pgs[i];
345 		if (pg == NULL)
346 			continue;
347 
348 		KASSERT(pg->flags & PG_BUSY);
349 		if (pg->flags & PG_WANTED)
350 			wakeup(pg);
351 		if (pg->flags & PG_RELEASED)
352 			uvm_pagefree(pg);
353 		else
354 			pg->flags &= ~(PG_WANTED|PG_BUSY);
355 	}
356 }
357 
358 void
359 uvm_estimatepageable(int *active, int *inactive)
360 {
361 
362 	/* XXX: guessing game */
363 	*active = 1024;
364 	*inactive = 1024;
365 }
366 
367 struct vm_map_kernel *
368 vm_map_to_kernel(struct vm_map *map)
369 {
370 
371 	return (struct vm_map_kernel *)map;
372 }
373 
374 bool
375 vm_map_starved_p(struct vm_map *map)
376 {
377 
378 	return false;
379 }
380 
381 void
382 uvm_pageout_start(int npages)
383 {
384 
385 	uvmexp.paging += npages;
386 }
387 
388 void
389 uvm_pageout_done(int npages)
390 {
391 
392 	uvmexp.paging -= npages;
393 
394 	/*
395 	 * wake up either of pagedaemon or LWPs waiting for it.
396 	 */
397 
398 	if (uvmexp.free <= uvmexp.reserve_kernel) {
399 		wakeup(&uvm.pagedaemon);
400 	} else {
401 		wakeup(&uvmexp.free);
402 	}
403 }
404 
405 /* XXX: following two are unfinished because lwp's are not refcounted yet */
406 void
407 uvm_lwp_hold(struct lwp *l)
408 {
409 
410 	atomic_inc_uint(&l->l_holdcnt);
411 }
412 
413 void
414 uvm_lwp_rele(struct lwp *l)
415 {
416 
417 	atomic_dec_uint(&l->l_holdcnt);
418 }
419 
420 int
421 uvm_loan(struct vm_map *map, vaddr_t start, vsize_t len, void *v, int flags)
422 {
423 
424 	panic("%s: unimplemented", __func__);
425 }
426 
427 void
428 uvm_unloan(void *v, int npages, int flags)
429 {
430 
431 	panic("%s: unimplemented", __func__);
432 }
433 
434 int
435 uvm_loanuobjpages(struct uvm_object *uobj, voff_t pgoff, int orignpages,
436 	struct vm_page **opp)
437 {
438 
439 	panic("%s: unimplemented", __func__);
440 }
441 
442 /*
443  * Kmem
444  */
445 
446 #ifndef RUMP_USE_REAL_ALLOCATORS
447 void *
448 kmem_alloc(size_t size, km_flag_t kmflag)
449 {
450 
451 	return rumpuser_malloc(size, kmflag == KM_NOSLEEP);
452 }
453 
454 void *
455 kmem_zalloc(size_t size, km_flag_t kmflag)
456 {
457 	void *rv;
458 
459 	rv = kmem_alloc(size, kmflag);
460 	if (rv)
461 		memset(rv, 0, size);
462 
463 	return rv;
464 }
465 
466 void
467 kmem_free(void *p, size_t size)
468 {
469 
470 	rumpuser_free(p);
471 }
472 #endif /* RUMP_USE_REAL_ALLOCATORS */
473 
474 /*
475  * UVM km
476  */
477 
478 vaddr_t
479 uvm_km_alloc(struct vm_map *map, vsize_t size, vsize_t align, uvm_flag_t flags)
480 {
481 	void *rv;
482 	int alignbit, error;
483 
484 	alignbit = 0;
485 	if (align) {
486 		alignbit = ffs(align)-1;
487 	}
488 
489 	rv = rumpuser_anonmmap(size, alignbit, flags & UVM_KMF_EXEC, &error);
490 	if (rv == NULL) {
491 		if (flags & (UVM_KMF_CANFAIL | UVM_KMF_NOWAIT))
492 			return 0;
493 		else
494 			panic("uvm_km_alloc failed");
495 	}
496 
497 	if (flags & UVM_KMF_ZERO)
498 		memset(rv, 0, size);
499 
500 	return (vaddr_t)rv;
501 }
502 
503 void
504 uvm_km_free(struct vm_map *map, vaddr_t vaddr, vsize_t size, uvm_flag_t flags)
505 {
506 
507 	rumpuser_unmap((void *)vaddr, size);
508 }
509 
510 struct vm_map *
511 uvm_km_suballoc(struct vm_map *map, vaddr_t *minaddr, vaddr_t *maxaddr,
512 	vsize_t size, int pageable, bool fixed, struct vm_map_kernel *submap)
513 {
514 
515 	return (struct vm_map *)417416;
516 }
517 
518 vaddr_t
519 uvm_km_alloc_poolpage(struct vm_map *map, bool waitok)
520 {
521 
522 	return (vaddr_t)rumpuser_malloc(PAGE_SIZE, !waitok);
523 }
524 
525 void
526 uvm_km_free_poolpage(struct vm_map *map, vaddr_t addr)
527 {
528 
529 	rumpuser_unmap((void *)addr, PAGE_SIZE);
530 }
531 
532 vaddr_t
533 uvm_km_alloc_poolpage_cache(struct vm_map *map, bool waitok)
534 {
535 	void *rv;
536 	int error;
537 
538 	rv = rumpuser_anonmmap(PAGE_SIZE, PAGE_SHIFT, 0, &error);
539 	if (rv == NULL && waitok)
540 		panic("fixme: poolpage alloc failed");
541 
542 	return (vaddr_t)rv;
543 }
544 
545 void
546 uvm_km_free_poolpage_cache(struct vm_map *map, vaddr_t vaddr)
547 {
548 
549 	rumpuser_unmap((void *)vaddr, PAGE_SIZE);
550 }
551