Line data Source code
1 : /* $OpenBSD: uvm_glue.c,v 1.73 2017/05/08 09:32:19 mpi Exp $ */
2 : /* $NetBSD: uvm_glue.c,v 1.44 2001/02/06 19:54:44 eeh Exp $ */
3 :
4 : /*
5 : * Copyright (c) 1997 Charles D. Cranor and Washington University.
6 : * Copyright (c) 1991, 1993, The Regents of the University of California.
7 : *
8 : * All rights reserved.
9 : *
10 : * This code is derived from software contributed to Berkeley by
11 : * The Mach Operating System project at Carnegie-Mellon University.
12 : *
13 : * Redistribution and use in source and binary forms, with or without
14 : * modification, are permitted provided that the following conditions
15 : * are met:
16 : * 1. Redistributions of source code must retain the above copyright
17 : * notice, this list of conditions and the following disclaimer.
18 : * 2. Redistributions in binary form must reproduce the above copyright
19 : * notice, this list of conditions and the following disclaimer in the
20 : * documentation and/or other materials provided with the distribution.
21 : * 3. Neither the name of the University nor the names of its contributors
22 : * may be used to endorse or promote products derived from this software
23 : * without specific prior written permission.
24 : *
25 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 : * SUCH DAMAGE.
36 : *
37 : * @(#)vm_glue.c 8.6 (Berkeley) 1/5/94
38 : * from: Id: uvm_glue.c,v 1.1.2.8 1998/02/07 01:16:54 chs Exp
39 : *
40 : *
41 : * Copyright (c) 1987, 1990 Carnegie-Mellon University.
42 : * All rights reserved.
43 : *
44 : * Permission to use, copy, modify and distribute this software and
45 : * its documentation is hereby granted, provided that both the copyright
46 : * notice and this permission notice appear in all copies of the
47 : * software, derivative works or modified versions, and any portions
48 : * thereof, and that both notices appear in supporting documentation.
49 : *
50 : * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
51 : * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND
52 : * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
53 : *
54 : * Carnegie Mellon requests users of this software to return to
55 : *
56 : * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
57 : * School of Computer Science
58 : * Carnegie Mellon University
59 : * Pittsburgh PA 15213-3890
60 : *
61 : * any improvements or extensions that they make and grant Carnegie the
62 : * rights to redistribute these changes.
63 : */
64 :
65 : /*
66 : * uvm_glue.c: glue functions
67 : */
68 :
69 : #include <sys/param.h>
70 : #include <sys/systm.h>
71 : #include <sys/proc.h>
72 : #include <sys/resourcevar.h>
73 : #include <sys/buf.h>
74 : #include <sys/user.h>
75 : #ifdef SYSVSHM
76 : #include <sys/shm.h>
77 : #endif
78 : #include <sys/sched.h>
79 :
80 : #include <uvm/uvm.h>
81 :
82 : /*
83 : * uvm_kernacc: can the kernel access a region of memory
84 : *
85 : * - called from malloc [DIAGNOSTIC], and /dev/kmem driver (mem.c)
86 : */
87 : boolean_t
88 0 : uvm_kernacc(caddr_t addr, size_t len, int rw)
89 : {
90 : boolean_t rv;
91 : vaddr_t saddr, eaddr;
92 0 : vm_prot_t prot = rw == B_READ ? PROT_READ : PROT_WRITE;
93 :
94 0 : saddr = trunc_page((vaddr_t)addr);
95 0 : eaddr = round_page((vaddr_t)addr + len);
96 0 : vm_map_lock_read(kernel_map);
97 0 : rv = uvm_map_checkprot(kernel_map, saddr, eaddr, prot);
98 0 : vm_map_unlock_read(kernel_map);
99 :
100 0 : return(rv);
101 : }
102 :
103 : /*
104 : * uvm_vslock: wire user memory for I/O
105 : *
106 : * - called from physio and sys_sysctl
107 : */
108 :
109 : int
110 0 : uvm_vslock(struct proc *p, caddr_t addr, size_t len, vm_prot_t access_type)
111 : {
112 : struct vm_map *map;
113 : vaddr_t start, end;
114 : int rv;
115 :
116 0 : map = &p->p_vmspace->vm_map;
117 0 : start = trunc_page((vaddr_t)addr);
118 0 : end = round_page((vaddr_t)addr + len);
119 0 : if (end <= start)
120 0 : return (EINVAL);
121 :
122 0 : rv = uvm_fault_wire(map, start, end, access_type);
123 :
124 0 : return (rv);
125 0 : }
126 :
127 : /*
128 : * uvm_vsunlock: unwire user memory wired by uvm_vslock()
129 : *
130 : * - called from physio and sys_sysctl
131 : */
132 :
133 : void
134 0 : uvm_vsunlock(struct proc *p, caddr_t addr, size_t len)
135 : {
136 : vaddr_t start, end;
137 :
138 0 : start = trunc_page((vaddr_t)addr);
139 0 : end = round_page((vaddr_t)addr + len);
140 0 : if (end <= start)
141 0 : return;
142 :
143 0 : uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
144 0 : }
145 :
146 : /*
147 : * uvm_vslock_device: wire user memory, make sure it's device reachable
148 : * and bounce if necessary.
149 : * Always bounces for now.
150 : */
151 : int
152 0 : uvm_vslock_device(struct proc *p, void *addr, size_t len,
153 : vm_prot_t access_type, void **retp)
154 : {
155 : struct vm_page *pg;
156 0 : struct pglist pgl;
157 : int npages;
158 : vaddr_t start, end, off;
159 : vaddr_t sva, va;
160 : vsize_t sz;
161 : int error, i;
162 :
163 0 : start = trunc_page((vaddr_t)addr);
164 0 : end = round_page((vaddr_t)addr + len);
165 0 : sz = end - start;
166 0 : off = (vaddr_t)addr - start;
167 0 : if (end <= start)
168 0 : return (EINVAL);
169 :
170 0 : if ((error = uvm_fault_wire(&p->p_vmspace->vm_map, start, end,
171 : access_type))) {
172 0 : return (error);
173 : }
174 :
175 0 : npages = atop(sz);
176 0 : for (i = 0; i < npages; i++) {
177 0 : paddr_t pa;
178 :
179 0 : if (!pmap_extract(p->p_vmspace->vm_map.pmap,
180 0 : start + ptoa(i), &pa)) {
181 : error = EFAULT;
182 0 : goto out_unwire;
183 : }
184 0 : if (!PADDR_IS_DMA_REACHABLE(pa))
185 0 : break;
186 0 : }
187 0 : if (i == npages) {
188 0 : *retp = NULL;
189 0 : return (0);
190 : }
191 :
192 0 : if ((va = uvm_km_valloc(kernel_map, sz)) == 0) {
193 : error = ENOMEM;
194 0 : goto out_unwire;
195 : }
196 : sva = va;
197 :
198 0 : TAILQ_INIT(&pgl);
199 0 : error = uvm_pglistalloc(npages * PAGE_SIZE, dma_constraint.ucr_low,
200 0 : dma_constraint.ucr_high, 0, 0, &pgl, npages, UVM_PLA_WAITOK);
201 0 : if (error)
202 : goto out_unmap;
203 :
204 0 : while ((pg = TAILQ_FIRST(&pgl)) != NULL) {
205 0 : TAILQ_REMOVE(&pgl, pg, pageq);
206 0 : pmap_kenter_pa(va, VM_PAGE_TO_PHYS(pg), PROT_READ | PROT_WRITE);
207 0 : va += PAGE_SIZE;
208 : }
209 : pmap_update(pmap_kernel());
210 0 : KASSERT(va == sva + sz);
211 0 : *retp = (void *)(sva + off);
212 :
213 0 : if ((error = copyin(addr, *retp, len)) == 0)
214 0 : return 0;
215 :
216 0 : uvm_km_pgremove_intrsafe(sva, sva + sz);
217 0 : pmap_kremove(sva, sz);
218 : pmap_update(pmap_kernel());
219 : out_unmap:
220 0 : uvm_km_free(kernel_map, sva, sz);
221 : out_unwire:
222 0 : uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
223 0 : return (error);
224 0 : }
225 :
226 : void
227 0 : uvm_vsunlock_device(struct proc *p, void *addr, size_t len, void *map)
228 : {
229 : vaddr_t start, end;
230 : vaddr_t kva;
231 : vsize_t sz;
232 :
233 0 : start = trunc_page((vaddr_t)addr);
234 0 : end = round_page((vaddr_t)addr + len);
235 0 : sz = end - start;
236 0 : if (end <= start)
237 0 : return;
238 :
239 0 : if (map)
240 0 : copyout(map, addr, len);
241 0 : uvm_fault_unwire(&p->p_vmspace->vm_map, start, end);
242 :
243 0 : if (!map)
244 0 : return;
245 :
246 0 : kva = trunc_page((vaddr_t)map);
247 0 : uvm_km_pgremove_intrsafe(kva, kva + sz);
248 0 : pmap_kremove(kva, sz);
249 : pmap_update(pmap_kernel());
250 0 : uvm_km_free(kernel_map, kva, sz);
251 0 : }
252 :
253 : /*
254 : * uvm_uarea_alloc: allocate the u-area for a new thread
255 : */
256 : vaddr_t
257 0 : uvm_uarea_alloc(void)
258 : {
259 : vaddr_t uaddr;
260 :
261 0 : uaddr = uvm_km_kmemalloc_pla(kernel_map, uvm.kernel_object, USPACE,
262 : USPACE_ALIGN, UVM_KMF_ZERO,
263 0 : no_constraint.ucr_low, no_constraint.ucr_high,
264 : 0, 0, USPACE/PAGE_SIZE);
265 :
266 0 : return (uaddr);
267 : }
268 :
269 : /*
270 : * uvm_uarea_free: free a dead thread's stack
271 : *
272 : * - the thread passed to us is a dead thread; we
273 : * are running on a different context now (the reaper).
274 : */
275 : void
276 0 : uvm_uarea_free(struct proc *p)
277 : {
278 0 : uvm_km_free(kernel_map, (vaddr_t)p->p_addr, USPACE);
279 0 : p->p_addr = NULL;
280 0 : }
281 :
282 : /*
283 : * uvm_exit: exit a virtual address space
284 : */
285 : void
286 0 : uvm_exit(struct process *pr)
287 : {
288 0 : uvmspace_free(pr->ps_vmspace);
289 0 : pr->ps_vmspace = NULL;
290 0 : }
291 :
292 : /*
293 : * uvm_init_limit: init per-process VM limits
294 : *
295 : * - called for process 0 and then inherited by all others.
296 : */
297 : void
298 0 : uvm_init_limits(struct proc *p)
299 : {
300 :
301 : /*
302 : * Set up the initial limits on process VM. Set the maximum
303 : * resident set size to be all of (reasonably) available memory.
304 : * This causes any single, large process to start random page
305 : * replacement once it fills memory.
306 : */
307 0 : p->p_rlimit[RLIMIT_STACK].rlim_cur = DFLSSIZ;
308 0 : p->p_rlimit[RLIMIT_STACK].rlim_max = MAXSSIZ;
309 0 : p->p_rlimit[RLIMIT_DATA].rlim_cur = DFLDSIZ;
310 0 : p->p_rlimit[RLIMIT_DATA].rlim_max = MAXDSIZ;
311 0 : p->p_rlimit[RLIMIT_RSS].rlim_cur = ptoa(uvmexp.free);
312 0 : }
313 :
314 : #ifdef DEBUG
315 : int enableswap = 1;
316 : int swapdebug = 0;
317 : #define SDB_FOLLOW 1
318 : #define SDB_SWAPIN 2
319 : #define SDB_SWAPOUT 4
320 : #endif
321 :
322 :
323 : /*
324 : * swapout_threads: find threads that can be swapped
325 : *
326 : * - called by the pagedaemon
327 : * - try and swap at least one processs
328 : * - processes that are sleeping or stopped for maxslp or more seconds
329 : * are swapped... otherwise the longest-sleeping or stopped process
330 : * is swapped, otherwise the longest resident process...
331 : */
332 : void
333 0 : uvm_swapout_threads(void)
334 : {
335 : struct process *pr;
336 : struct proc *p, *slpp;
337 : struct process *outpr;
338 : int outpri;
339 : int didswap = 0;
340 : extern int maxslp;
341 : /* XXXCDC: should move off to uvmexp. or uvm., also in uvm_meter */
342 :
343 : #ifdef DEBUG
344 : if (!enableswap)
345 : return;
346 : #endif
347 :
348 : /*
349 : * outpr/outpri : stop/sleep process whose most active thread has
350 : * the largest sleeptime < maxslp
351 : */
352 : outpr = NULL;
353 : outpri = 0;
354 0 : LIST_FOREACH(pr, &allprocess, ps_list) {
355 0 : if (pr->ps_flags & (PS_SYSTEM | PS_EXITING))
356 : continue;
357 :
358 : /*
359 : * slpp: the sleeping or stopped thread in pr with
360 : * the smallest p_slptime
361 : */
362 : slpp = NULL;
363 0 : TAILQ_FOREACH(p, &pr->ps_threads, p_thr_link) {
364 0 : switch (p->p_stat) {
365 : case SRUN:
366 : case SONPROC:
367 : goto next_process;
368 :
369 : case SSLEEP:
370 : case SSTOP:
371 0 : if (slpp == NULL ||
372 0 : slpp->p_slptime < p->p_slptime)
373 0 : slpp = p;
374 : continue;
375 : }
376 : }
377 :
378 0 : if (slpp != NULL) {
379 0 : if (slpp->p_slptime >= maxslp) {
380 0 : pmap_collect(pr->ps_vmspace->vm_map.pmap);
381 0 : didswap++;
382 0 : } else if (slpp->p_slptime > outpri) {
383 : outpr = pr;
384 : outpri = slpp->p_slptime;
385 0 : }
386 : }
387 : next_process: ;
388 : }
389 :
390 : /*
391 : * If we didn't get rid of any real duds, toss out the next most
392 : * likely sleeping/stopped or running candidate. We only do this
393 : * if we are real low on memory since we don't gain much by doing
394 : * it.
395 : */
396 0 : if (didswap == 0 && uvmexp.free <= atop(round_page(USPACE)) &&
397 0 : outpr != NULL) {
398 : #ifdef DEBUG
399 : if (swapdebug & SDB_SWAPOUT)
400 : printf("swapout_threads: no duds, try procpr %p\n",
401 : outpr);
402 : #endif
403 0 : pmap_collect(outpr->ps_vmspace->vm_map.pmap);
404 0 : }
405 0 : }
406 :
407 : /*
408 : * uvm_atopg: convert KVAs back to their page structures.
409 : */
410 : struct vm_page *
411 0 : uvm_atopg(vaddr_t kva)
412 : {
413 : struct vm_page *pg;
414 0 : paddr_t pa;
415 : boolean_t rv;
416 :
417 0 : rv = pmap_extract(pmap_kernel(), kva, &pa);
418 0 : KASSERT(rv);
419 0 : pg = PHYS_TO_VM_PAGE(pa);
420 0 : KASSERT(pg != NULL);
421 0 : return (pg);
422 0 : }
423 :
424 : void
425 0 : uvm_pause(void)
426 : {
427 : static unsigned int toggle;
428 0 : if (toggle++ > 128) {
429 0 : toggle = 0;
430 0 : KERNEL_UNLOCK();
431 0 : KERNEL_LOCK();
432 0 : }
433 0 : sched_pause(preempt);
434 0 : }
435 :
436 : #ifndef SMALL_KERNEL
437 : int
438 0 : fill_vmmap(struct process *pr, struct kinfo_vmentry *kve,
439 : size_t *lenp)
440 : {
441 : struct vm_map *map;
442 :
443 0 : if (pr != NULL)
444 0 : map = &pr->ps_vmspace->vm_map;
445 : else
446 0 : map = kernel_map;
447 0 : return uvm_map_fill_vmmap(map, kve, lenp);
448 : }
449 : #endif
|