xref: /dflybsd-src/sys/vm/vm_vmspace.c (revision 5229377c915d2a82af954d67267edb514bfcca3f)
1133aabc4SMatthew Dillon /*
2af2b4857SMatthew Dillon  * (MPSAFE)
3af2b4857SMatthew Dillon  *
4133aabc4SMatthew Dillon  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
5133aabc4SMatthew Dillon  *
6133aabc4SMatthew Dillon  * This code is derived from software contributed to The DragonFly Project
7133aabc4SMatthew Dillon  * by Matthew Dillon <dillon@backplane.com>
8133aabc4SMatthew Dillon  *
9133aabc4SMatthew Dillon  * Redistribution and use in source and binary forms, with or without
10133aabc4SMatthew Dillon  * modification, are permitted provided that the following conditions
11133aabc4SMatthew Dillon  * are met:
12133aabc4SMatthew Dillon  *
13133aabc4SMatthew Dillon  * 1. Redistributions of source code must retain the above copyright
14133aabc4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer.
15133aabc4SMatthew Dillon  * 2. Redistributions in binary form must reproduce the above copyright
16133aabc4SMatthew Dillon  *    notice, this list of conditions and the following disclaimer in
17133aabc4SMatthew Dillon  *    the documentation and/or other materials provided with the
18133aabc4SMatthew Dillon  *    distribution.
19133aabc4SMatthew Dillon  * 3. Neither the name of The DragonFly Project nor the names of its
20133aabc4SMatthew Dillon  *    contributors may be used to endorse or promote products derived
21133aabc4SMatthew Dillon  *    from this software without specific, prior written permission.
22133aabc4SMatthew Dillon  *
23133aabc4SMatthew Dillon  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24133aabc4SMatthew Dillon  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25133aabc4SMatthew Dillon  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26133aabc4SMatthew Dillon  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27133aabc4SMatthew Dillon  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28133aabc4SMatthew Dillon  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29133aabc4SMatthew Dillon  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30133aabc4SMatthew Dillon  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31133aabc4SMatthew Dillon  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32133aabc4SMatthew Dillon  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33133aabc4SMatthew Dillon  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34133aabc4SMatthew Dillon  * SUCH DAMAGE.
35133aabc4SMatthew Dillon  */
36133aabc4SMatthew Dillon 
37133aabc4SMatthew Dillon #include <sys/param.h>
38133aabc4SMatthew Dillon #include <sys/kernel.h>
39133aabc4SMatthew Dillon #include <sys/systm.h>
4080d831e1SMatthew Dillon #include <sys/sysmsg.h>
41021a4ed4SMatthew Dillon #include <sys/kern_syscall.h>
42d3313941SMatthew Dillon #include <sys/mman.h>
43af2b4857SMatthew Dillon #include <sys/thread.h>
44d3313941SMatthew Dillon #include <sys/proc.h>
45d3313941SMatthew Dillon #include <sys/malloc.h>
46d3313941SMatthew Dillon #include <sys/sysctl.h>
47d3313941SMatthew Dillon #include <sys/vkernel.h>
484a22e893SMatthew Dillon #include <sys/vmspace.h>
49d3313941SMatthew Dillon 
50d3313941SMatthew Dillon #include <vm/vm_extern.h>
51d3313941SMatthew Dillon #include <vm/pmap.h>
52d3313941SMatthew Dillon 
53c439ad8fSMatthew Dillon #include <machine/vmparam.h>
54c439ad8fSMatthew Dillon 
5539005e16SMatthew Dillon static struct vmspace_entry *vkernel_find_vmspace(struct vkernel_proc *vkp,
56d95d5e03SMatthew Dillon 						  void *id, int havetoken);
5776f1911eSMatthew Dillon static int vmspace_entry_delete(struct vmspace_entry *ve,
5876f1911eSMatthew Dillon 				 struct vkernel_proc *vkp, int refs);
5976f1911eSMatthew Dillon static void vmspace_entry_cache_ref(struct vmspace_entry *ve);
6076f1911eSMatthew Dillon static void vmspace_entry_cache_drop(struct vmspace_entry *ve);
61d95d5e03SMatthew Dillon static void vmspace_entry_drop(struct vmspace_entry *ve);
62d3313941SMatthew Dillon 
63d3313941SMatthew Dillon static MALLOC_DEFINE(M_VKERNEL, "vkernel", "VKernel structures");
64133aabc4SMatthew Dillon 
65133aabc4SMatthew Dillon /*
66d3313941SMatthew Dillon  * vmspace_create (void *id, int type, void *data)
67133aabc4SMatthew Dillon  *
68d3313941SMatthew Dillon  * Create a VMSPACE under the control of the caller with the specified id.
69d3313941SMatthew Dillon  * An id of NULL cannot be used.  The type and data fields must currently
70d3313941SMatthew Dillon  * be 0.
71133aabc4SMatthew Dillon  *
72d3313941SMatthew Dillon  * The vmspace starts out completely empty.  Memory may be mapped into the
73*4d4f84f5SMatthew Dillon  * VMSPACE with vmspace_mmap().
743919ced0SMatthew Dillon  *
75af2b4857SMatthew Dillon  * No requirements.
76d3313941SMatthew Dillon  */
77d3313941SMatthew Dillon int
sys_vmspace_create(struct sysmsg * sysmsg,const struct vmspace_create_args * uap)7880d831e1SMatthew Dillon sys_vmspace_create(struct sysmsg *sysmsg,
7980d831e1SMatthew Dillon 		   const struct vmspace_create_args *uap)
80d3313941SMatthew Dillon {
81d3313941SMatthew Dillon 	struct vmspace_entry *ve;
8239005e16SMatthew Dillon 	struct vkernel_proc *vkp;
83af2b4857SMatthew Dillon 	struct proc *p = curproc;
843919ced0SMatthew Dillon 	int error;
85d3313941SMatthew Dillon 
86d3313941SMatthew Dillon 	if (vkernel_enable == 0)
87d3313941SMatthew Dillon 		return (EOPNOTSUPP);
88d3313941SMatthew Dillon 
89d3313941SMatthew Dillon 	/*
90d3313941SMatthew Dillon 	 * Create a virtual kernel side-structure for the process if one
91d3313941SMatthew Dillon 	 * does not exist.
92af2b4857SMatthew Dillon 	 *
93af2b4857SMatthew Dillon 	 * Implement a simple resolution for SMP races.
94d3313941SMatthew Dillon 	 */
95af2b4857SMatthew Dillon 	if ((vkp = p->p_vkernel) == NULL) {
9639005e16SMatthew Dillon 		vkp = kmalloc(sizeof(*vkp), M_VKERNEL, M_WAITOK|M_ZERO);
97a8d3ab53SMatthew Dillon 		lwkt_gettoken(&p->p_token);
98af2b4857SMatthew Dillon 		if (p->p_vkernel == NULL) {
9939005e16SMatthew Dillon 			vkp->refs = 1;
100a3c18566SMatthew Dillon 			lwkt_token_init(&vkp->token, "vkernel");
10139005e16SMatthew Dillon 			RB_INIT(&vkp->root);
102af2b4857SMatthew Dillon 			p->p_vkernel = vkp;
103af2b4857SMatthew Dillon 		} else {
104af2b4857SMatthew Dillon 			kfree(vkp, M_VKERNEL);
105af2b4857SMatthew Dillon 			vkp = p->p_vkernel;
106af2b4857SMatthew Dillon 		}
107a8d3ab53SMatthew Dillon 		lwkt_reltoken(&p->p_token);
108d3313941SMatthew Dillon 	}
109d3313941SMatthew Dillon 
110d3313941SMatthew Dillon 	/*
111af2b4857SMatthew Dillon 	 * Create a new VMSPACE, disallow conflicting ids
112d3313941SMatthew Dillon 	 */
113d3313941SMatthew Dillon 	ve = kmalloc(sizeof(struct vmspace_entry), M_VKERNEL, M_WAITOK|M_ZERO);
11488181b08SMatthew Dillon 	ve->vmspace = vmspace_alloc(VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
115d3313941SMatthew Dillon 	ve->id = uap->id;
1161e0d343fSMatthew Dillon 	ve->refs = 0;		/* active refs (none) */
1171e0d343fSMatthew Dillon 	ve->cache_refs = 1;	/* on-tree, not deleted (prevent kfree) */
118d3313941SMatthew Dillon 	pmap_pinit2(vmspace_pmap(ve->vmspace));
119af2b4857SMatthew Dillon 
120af2b4857SMatthew Dillon 	lwkt_gettoken(&vkp->token);
121af2b4857SMatthew Dillon 	if (RB_INSERT(vmspace_rb_tree, &vkp->root, ve)) {
12293f86408SMatthew Dillon 		vmspace_rel(ve->vmspace);
123a2ee730dSMatthew Dillon 		ve->vmspace = NULL; /* safety */
124af2b4857SMatthew Dillon 		kfree(ve, M_VKERNEL);
125af2b4857SMatthew Dillon 		error = EEXIST;
126af2b4857SMatthew Dillon 	} else {
1273919ced0SMatthew Dillon 		error = 0;
128af2b4857SMatthew Dillon 	}
129af2b4857SMatthew Dillon 	lwkt_reltoken(&vkp->token);
130a86ce0cdSMatthew Dillon 
1313919ced0SMatthew Dillon 	return (error);
132d3313941SMatthew Dillon }
133d3313941SMatthew Dillon 
134d3313941SMatthew Dillon /*
135af2b4857SMatthew Dillon  * Destroy a VMSPACE given its identifier.
136133aabc4SMatthew Dillon  *
137af2b4857SMatthew Dillon  * No requirements.
138d3313941SMatthew Dillon  */
139d3313941SMatthew Dillon int
sys_vmspace_destroy(struct sysmsg * sysmsg,const struct vmspace_destroy_args * uap)14080d831e1SMatthew Dillon sys_vmspace_destroy(struct sysmsg *sysmsg,
14180d831e1SMatthew Dillon 		    const struct vmspace_destroy_args *uap)
142d3313941SMatthew Dillon {
14339005e16SMatthew Dillon 	struct vkernel_proc *vkp;
144d3313941SMatthew Dillon 	struct vmspace_entry *ve;
1453919ced0SMatthew Dillon 	int error;
146d3313941SMatthew Dillon 
14776f1911eSMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL)
14876f1911eSMatthew Dillon 		return EINVAL;
14976f1911eSMatthew Dillon 
15076f1911eSMatthew Dillon 	/*
15176f1911eSMatthew Dillon 	 * vkp->token protects the deletion against a new RB tree search.
15276f1911eSMatthew Dillon 	 */
153af2b4857SMatthew Dillon 	lwkt_gettoken(&vkp->token);
1543919ced0SMatthew Dillon 	error = ENOENT;
15576f1911eSMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 1)) != NULL) {
1561e0d343fSMatthew Dillon 		error = vmspace_entry_delete(ve, vkp, 1);
1571e0d343fSMatthew Dillon 		if (error == 0)
1581e0d343fSMatthew Dillon 			vmspace_entry_cache_drop(ve);
1593919ced0SMatthew Dillon 	}
160af2b4857SMatthew Dillon 	lwkt_reltoken(&vkp->token);
16176f1911eSMatthew Dillon 
1623919ced0SMatthew Dillon 	return(error);
163d3313941SMatthew Dillon }
164d3313941SMatthew Dillon 
165d3313941SMatthew Dillon /*
1664e7c41c5SMatthew Dillon  * vmspace_ctl (void *id, int cmd, struct trapframe *tframe,
1674e7c41c5SMatthew Dillon  *		struct vextframe *vframe);
168d3313941SMatthew Dillon  *
169d3313941SMatthew Dillon  * Transfer control to a VMSPACE.  Control is returned after the specified
170d3313941SMatthew Dillon  * number of microseconds or if a page fault, signal, trap, or system call
171021a4ed4SMatthew Dillon  * occurs.  The context is updated as appropriate.
1723919ced0SMatthew Dillon  *
173af2b4857SMatthew Dillon  * No requirements.
174133aabc4SMatthew Dillon  */
175133aabc4SMatthew Dillon int
sys_vmspace_ctl(struct sysmsg * sysmsg,const struct vmspace_ctl_args * uap)17680d831e1SMatthew Dillon sys_vmspace_ctl(struct sysmsg *sysmsg,
17780d831e1SMatthew Dillon 		const struct vmspace_ctl_args *uap)
178133aabc4SMatthew Dillon {
17925206fdbSMatthew Dillon 	struct vmspace_ctl_args ua = *uap;
18039005e16SMatthew Dillon 	struct vkernel_proc *vkp;
18139005e16SMatthew Dillon 	struct vkernel_lwp *vklp;
182a86ce0cdSMatthew Dillon 	struct vmspace_entry *ve = NULL;
18339005e16SMatthew Dillon 	struct lwp *lp;
1844a22e893SMatthew Dillon 	struct proc *p;
1854a22e893SMatthew Dillon 	int framesz;
1864a22e893SMatthew Dillon 	int error;
187d3313941SMatthew Dillon 
18839005e16SMatthew Dillon 	lp = curthread->td_lwp;
18939005e16SMatthew Dillon 	p = lp->lwp_proc;
190287ebb09SMatthew Dillon 
191af2b4857SMatthew Dillon 	if ((vkp = p->p_vkernel) == NULL)
192af2b4857SMatthew Dillon 		return (EINVAL);
193af2b4857SMatthew Dillon 
194a86ce0cdSMatthew Dillon 	/*
19525206fdbSMatthew Dillon 	 * NOTE: We have to copy *uap into ua because uap is an aliased
19625206fdbSMatthew Dillon 	 *	 pointer into the sysframe, which we are replacing.
197a86ce0cdSMatthew Dillon 	 */
19825206fdbSMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, ua.id, 0)) == NULL) {
1993919ced0SMatthew Dillon 		error = ENOENT;
2003919ced0SMatthew Dillon 		goto done;
2013919ced0SMatthew Dillon 	}
2024a22e893SMatthew Dillon 
20325206fdbSMatthew Dillon 	switch(ua.cmd) {
2044a22e893SMatthew Dillon 	case VMSPACE_CTL_RUN:
2054a22e893SMatthew Dillon 		/*
2064a22e893SMatthew Dillon 		 * Save the caller's register context, swap VM spaces, and
2074a22e893SMatthew Dillon 		 * install the passed register context.  Return with
2084a22e893SMatthew Dillon 		 * EJUSTRETURN so the syscall code doesn't adjust the context.
2094a22e893SMatthew Dillon 		 */
2104a22e893SMatthew Dillon 		framesz = sizeof(struct trapframe);
21139005e16SMatthew Dillon 		if ((vklp = lp->lwp_vkernel) == NULL) {
21239005e16SMatthew Dillon 			vklp = kmalloc(sizeof(*vklp), M_VKERNEL,
21339005e16SMatthew Dillon 				       M_WAITOK|M_ZERO);
21439005e16SMatthew Dillon 			lp->lwp_vkernel = vklp;
21539005e16SMatthew Dillon 		}
216d95d5e03SMatthew Dillon 		if (ve && vklp->ve_cache != ve) {
21776f1911eSMatthew Dillon 			vmspace_entry_cache_ref(ve);
21876f1911eSMatthew Dillon 			if (vklp->ve_cache)
21976f1911eSMatthew Dillon 				vmspace_entry_cache_drop(vklp->ve_cache);
220d95d5e03SMatthew Dillon 			vklp->ve_cache = ve;
221d95d5e03SMatthew Dillon 		}
22225206fdbSMatthew Dillon 		vklp->user_trapframe = ua.tframe;
22325206fdbSMatthew Dillon 		vklp->user_vextframe = ua.vframe;
22480d831e1SMatthew Dillon 		bcopy(sysmsg->sysmsg_frame, &vklp->save_trapframe, framesz);
22539005e16SMatthew Dillon 		bcopy(&curthread->td_tls, &vklp->save_vextframe.vx_tls,
22639005e16SMatthew Dillon 		      sizeof(vklp->save_vextframe.vx_tls));
22725206fdbSMatthew Dillon 		error = copyin(ua.tframe, sysmsg->sysmsg_frame, framesz);
228af2b4857SMatthew Dillon 		if (error == 0) {
22925206fdbSMatthew Dillon 			error = copyin(&ua.vframe->vx_tls,
230af2b4857SMatthew Dillon 				       &curthread->td_tls,
231af2b4857SMatthew Dillon 				       sizeof(struct savetls));
232af2b4857SMatthew Dillon 		}
2334a22e893SMatthew Dillon 		if (error == 0)
23480d831e1SMatthew Dillon 			error = cpu_sanitize_frame(sysmsg->sysmsg_frame);
2354e7c41c5SMatthew Dillon 		if (error == 0)
2364e7c41c5SMatthew Dillon 			error = cpu_sanitize_tls(&curthread->td_tls);
2374a22e893SMatthew Dillon 		if (error) {
23880d831e1SMatthew Dillon 			bcopy(&vklp->save_trapframe, sysmsg->sysmsg_frame,
239af2b4857SMatthew Dillon 			      framesz);
24039005e16SMatthew Dillon 			bcopy(&vklp->save_vextframe.vx_tls, &curthread->td_tls,
24139005e16SMatthew Dillon 			      sizeof(vklp->save_vextframe.vx_tls));
2424e7c41c5SMatthew Dillon 			set_user_TLS();
2434a22e893SMatthew Dillon 		} else {
24439005e16SMatthew Dillon 			vklp->ve = ve;
245d95d5e03SMatthew Dillon 			atomic_add_int(&ve->refs, 1);
24639005e16SMatthew Dillon 			pmap_setlwpvm(lp, ve->vmspace);
2474e7c41c5SMatthew Dillon 			set_user_TLS();
24880d831e1SMatthew Dillon 			set_vkernel_fp(sysmsg->sysmsg_frame);
2494a22e893SMatthew Dillon 			error = EJUSTRETURN;
2504a22e893SMatthew Dillon 		}
2514a22e893SMatthew Dillon 		break;
2524a22e893SMatthew Dillon 	default:
2534a22e893SMatthew Dillon 		error = EOPNOTSUPP;
2544a22e893SMatthew Dillon 		break;
2554a22e893SMatthew Dillon 	}
2563919ced0SMatthew Dillon done:
257d95d5e03SMatthew Dillon 	if (ve)
258d95d5e03SMatthew Dillon 		vmspace_entry_drop(ve);
259d95d5e03SMatthew Dillon 
2604a22e893SMatthew Dillon 	return(error);
261133aabc4SMatthew Dillon }
262133aabc4SMatthew Dillon 
263133aabc4SMatthew Dillon /*
264d3313941SMatthew Dillon  * vmspace_mmap(id, addr, len, prot, flags, fd, offset)
265133aabc4SMatthew Dillon  *
266d3313941SMatthew Dillon  * map memory within a VMSPACE.  This function is just like a normal mmap()
267*4d4f84f5SMatthew Dillon  * but operates on the vmspace's memory map.
2683919ced0SMatthew Dillon  *
2693de6dc48SVenkatesh Srinivas  * No requirements.
270133aabc4SMatthew Dillon  */
271133aabc4SMatthew Dillon int
sys_vmspace_mmap(struct sysmsg * sysmsg,const struct vmspace_mmap_args * uap)27280d831e1SMatthew Dillon sys_vmspace_mmap(struct sysmsg *sysmsg,
27380d831e1SMatthew Dillon 		 const struct vmspace_mmap_args *uap)
274133aabc4SMatthew Dillon {
27539005e16SMatthew Dillon 	struct vkernel_proc *vkp;
276d3313941SMatthew Dillon 	struct vmspace_entry *ve;
277021a4ed4SMatthew Dillon 	int error;
278d3313941SMatthew Dillon 
2793919ced0SMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL) {
2803919ced0SMatthew Dillon 		error = EINVAL;
281d95d5e03SMatthew Dillon 		goto done2;
2823919ced0SMatthew Dillon 	}
283af2b4857SMatthew Dillon 
284d95d5e03SMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 0)) == NULL) {
285d95d5e03SMatthew Dillon 		error = ENOENT;
286d95d5e03SMatthew Dillon 		goto done2;
287d95d5e03SMatthew Dillon 	}
288d95d5e03SMatthew Dillon 
289021a4ed4SMatthew Dillon 	error = kern_mmap(ve->vmspace, uap->addr, uap->len,
290021a4ed4SMatthew Dillon 			  uap->prot, uap->flags,
29180d831e1SMatthew Dillon 			  uap->fd, uap->offset, &sysmsg->sysmsg_resultp);
29276f1911eSMatthew Dillon 
293d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
294d95d5e03SMatthew Dillon done2:
295021a4ed4SMatthew Dillon 	return (error);
296133aabc4SMatthew Dillon }
297133aabc4SMatthew Dillon 
298133aabc4SMatthew Dillon /*
299d3313941SMatthew Dillon  * vmspace_munmap(id, addr, len)
300133aabc4SMatthew Dillon  *
301d3313941SMatthew Dillon  * unmap memory within a VMSPACE.
3023919ced0SMatthew Dillon  *
303af2b4857SMatthew Dillon  * No requirements.
304133aabc4SMatthew Dillon  */
305133aabc4SMatthew Dillon int
sys_vmspace_munmap(struct sysmsg * sysmsg,const struct vmspace_munmap_args * uap)30680d831e1SMatthew Dillon sys_vmspace_munmap(struct sysmsg *sysmsg,
30780d831e1SMatthew Dillon 		   const struct vmspace_munmap_args *uap)
308133aabc4SMatthew Dillon {
30939005e16SMatthew Dillon 	struct vkernel_proc *vkp;
310d3313941SMatthew Dillon 	struct vmspace_entry *ve;
311021a4ed4SMatthew Dillon 	vm_offset_t addr;
312e54488bbSMatthew Dillon 	vm_offset_t tmpaddr;
313021a4ed4SMatthew Dillon 	vm_size_t size, pageoff;
314021a4ed4SMatthew Dillon 	vm_map_t map;
3153919ced0SMatthew Dillon 	int error;
316021a4ed4SMatthew Dillon 
3173919ced0SMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL) {
3183919ced0SMatthew Dillon 		error = EINVAL;
319d95d5e03SMatthew Dillon 		goto done2;
3203919ced0SMatthew Dillon 	}
321d95d5e03SMatthew Dillon 
322d95d5e03SMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 0)) == NULL) {
3233919ced0SMatthew Dillon 		error = ENOENT;
324af2b4857SMatthew Dillon 		goto done2;
3253919ced0SMatthew Dillon 	}
326021a4ed4SMatthew Dillon 
327021a4ed4SMatthew Dillon 	/*
328af2b4857SMatthew Dillon 	 * NOTE: kern_munmap() can block so we need to temporarily
329af2b4857SMatthew Dillon 	 *	 ref ve->refs.
330af2b4857SMatthew Dillon 	 */
331af2b4857SMatthew Dillon 
332af2b4857SMatthew Dillon 	/*
333021a4ed4SMatthew Dillon 	 * Copied from sys_munmap()
334021a4ed4SMatthew Dillon 	 */
335021a4ed4SMatthew Dillon 	addr = (vm_offset_t)uap->addr;
336021a4ed4SMatthew Dillon 	size = uap->len;
337021a4ed4SMatthew Dillon 
338021a4ed4SMatthew Dillon 	pageoff = (addr & PAGE_MASK);
339021a4ed4SMatthew Dillon 	addr -= pageoff;
340021a4ed4SMatthew Dillon 	size += pageoff;
341021a4ed4SMatthew Dillon 	size = (vm_size_t)round_page(size);
3423919ced0SMatthew Dillon 	if (size < uap->len) {		/* wrap */
3433919ced0SMatthew Dillon 		error = EINVAL;
344af2b4857SMatthew Dillon 		goto done1;
3453919ced0SMatthew Dillon 	}
346e54488bbSMatthew Dillon 	tmpaddr = addr + size;		/* workaround gcc4 opt */
3473919ced0SMatthew Dillon 	if (tmpaddr < addr) {		/* wrap */
3483919ced0SMatthew Dillon 		error = EINVAL;
349af2b4857SMatthew Dillon 		goto done1;
3503919ced0SMatthew Dillon 	}
3513919ced0SMatthew Dillon 	if (size == 0) {
3523919ced0SMatthew Dillon 		error = 0;
353af2b4857SMatthew Dillon 		goto done1;
3543919ced0SMatthew Dillon 	}
355021a4ed4SMatthew Dillon 
3563919ced0SMatthew Dillon 	if (VM_MAX_USER_ADDRESS > 0 && tmpaddr > VM_MAX_USER_ADDRESS) {
3573919ced0SMatthew Dillon 		error = EINVAL;
358af2b4857SMatthew Dillon 		goto done1;
3593919ced0SMatthew Dillon 	}
3603919ced0SMatthew Dillon 	if (VM_MIN_USER_ADDRESS > 0 && addr < VM_MIN_USER_ADDRESS) {
3613919ced0SMatthew Dillon 		error = EINVAL;
362af2b4857SMatthew Dillon 		goto done1;
3633919ced0SMatthew Dillon 	}
364021a4ed4SMatthew Dillon 	map = &ve->vmspace->vm_map;
36546754a20SMatthew Dillon 	if (!vm_map_check_protection(map, addr, tmpaddr, VM_PROT_NONE, FALSE)) {
3663919ced0SMatthew Dillon 		error = EINVAL;
367af2b4857SMatthew Dillon 		goto done1;
3683919ced0SMatthew Dillon 	}
369021a4ed4SMatthew Dillon 	vm_map_remove(map, addr, addr + size);
3703919ced0SMatthew Dillon 	error = 0;
371af2b4857SMatthew Dillon done1:
372d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
373af2b4857SMatthew Dillon done2:
3743919ced0SMatthew Dillon 	return (error);
375021a4ed4SMatthew Dillon }
376021a4ed4SMatthew Dillon 
377021a4ed4SMatthew Dillon /*
378021a4ed4SMatthew Dillon  * vmspace_pread(id, buf, nbyte, flags, offset)
379021a4ed4SMatthew Dillon  *
380021a4ed4SMatthew Dillon  * Read data from a vmspace.  The number of bytes read is returned or
381021a4ed4SMatthew Dillon  * -1 if an unrecoverable error occured.  If the number of bytes read is
382021a4ed4SMatthew Dillon  * less then the request size, a page fault occured in the VMSPACE which
383021a4ed4SMatthew Dillon  * the caller must resolve in order to proceed.
3843919ced0SMatthew Dillon  *
3853919ced0SMatthew Dillon  * (not implemented yet)
386af2b4857SMatthew Dillon  * No requirements.
387021a4ed4SMatthew Dillon  */
388021a4ed4SMatthew Dillon int
sys_vmspace_pread(struct sysmsg * sysmsg,const struct vmspace_pread_args * uap)38980d831e1SMatthew Dillon sys_vmspace_pread(struct sysmsg *sysmsg,
39080d831e1SMatthew Dillon 		  const struct vmspace_pread_args *uap)
391021a4ed4SMatthew Dillon {
39239005e16SMatthew Dillon 	struct vkernel_proc *vkp;
393021a4ed4SMatthew Dillon 	struct vmspace_entry *ve;
3943919ced0SMatthew Dillon 	int error;
395021a4ed4SMatthew Dillon 
3963919ced0SMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL) {
3973919ced0SMatthew Dillon 		error = EINVAL;
398af2b4857SMatthew Dillon 		goto done3;
3993919ced0SMatthew Dillon 	}
400d95d5e03SMatthew Dillon 
401d95d5e03SMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 0)) == NULL) {
4023919ced0SMatthew Dillon 		error = ENOENT;
403d95d5e03SMatthew Dillon 		goto done3;
4043919ced0SMatthew Dillon 	}
405d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
4063919ced0SMatthew Dillon 	error = EINVAL;
407af2b4857SMatthew Dillon done3:
4083919ced0SMatthew Dillon 	return (error);
409021a4ed4SMatthew Dillon }
410021a4ed4SMatthew Dillon 
411021a4ed4SMatthew Dillon /*
412021a4ed4SMatthew Dillon  * vmspace_pwrite(id, buf, nbyte, flags, offset)
413021a4ed4SMatthew Dillon  *
414021a4ed4SMatthew Dillon  * Write data to a vmspace.  The number of bytes written is returned or
415021a4ed4SMatthew Dillon  * -1 if an unrecoverable error occured.  If the number of bytes written is
416021a4ed4SMatthew Dillon  * less then the request size, a page fault occured in the VMSPACE which
417021a4ed4SMatthew Dillon  * the caller must resolve in order to proceed.
4183919ced0SMatthew Dillon  *
4193919ced0SMatthew Dillon  * (not implemented yet)
420af2b4857SMatthew Dillon  * No requirements.
421021a4ed4SMatthew Dillon  */
422021a4ed4SMatthew Dillon int
sys_vmspace_pwrite(struct sysmsg * sysmsg,const struct vmspace_pwrite_args * uap)42380d831e1SMatthew Dillon sys_vmspace_pwrite(struct sysmsg *sysmsg,
42480d831e1SMatthew Dillon 		   const struct vmspace_pwrite_args *uap)
425021a4ed4SMatthew Dillon {
42639005e16SMatthew Dillon 	struct vkernel_proc *vkp;
427021a4ed4SMatthew Dillon 	struct vmspace_entry *ve;
4283919ced0SMatthew Dillon 	int error;
429d3313941SMatthew Dillon 
4303919ced0SMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL) {
4313919ced0SMatthew Dillon 		error = EINVAL;
432af2b4857SMatthew Dillon 		goto done3;
4333919ced0SMatthew Dillon 	}
434d95d5e03SMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 0)) == NULL) {
4353919ced0SMatthew Dillon 		error = ENOENT;
436d95d5e03SMatthew Dillon 		goto done3;
4373919ced0SMatthew Dillon 	}
438d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
4393919ced0SMatthew Dillon 	error = EINVAL;
440af2b4857SMatthew Dillon done3:
4413919ced0SMatthew Dillon 	return (error);
442133aabc4SMatthew Dillon }
443133aabc4SMatthew Dillon 
444133aabc4SMatthew Dillon /*
445d3313941SMatthew Dillon  * vmspace_mcontrol(id, addr, len, behav, value)
446133aabc4SMatthew Dillon  *
447d3313941SMatthew Dillon  * madvise/mcontrol support for a vmspace.
4483919ced0SMatthew Dillon  *
449af2b4857SMatthew Dillon  * No requirements.
450133aabc4SMatthew Dillon  */
451133aabc4SMatthew Dillon int
sys_vmspace_mcontrol(struct sysmsg * sysmsg,const struct vmspace_mcontrol_args * uap)45280d831e1SMatthew Dillon sys_vmspace_mcontrol(struct sysmsg *sysmsg,
45380d831e1SMatthew Dillon 		     const struct vmspace_mcontrol_args *uap)
454133aabc4SMatthew Dillon {
45539005e16SMatthew Dillon 	struct vkernel_proc *vkp;
456d3313941SMatthew Dillon 	struct vmspace_entry *ve;
457d95d5e03SMatthew Dillon 	struct lwp *lp;
458d3313941SMatthew Dillon 	vm_offset_t start, end;
459e54488bbSMatthew Dillon 	vm_offset_t tmpaddr = (vm_offset_t)uap->addr + uap->len;
4603919ced0SMatthew Dillon 	int error;
461d3313941SMatthew Dillon 
462d95d5e03SMatthew Dillon 	lp = curthread->td_lwp;
4633919ced0SMatthew Dillon 	if ((vkp = curproc->p_vkernel) == NULL) {
4643919ced0SMatthew Dillon 		error = EINVAL;
465af2b4857SMatthew Dillon 		goto done3;
4663919ced0SMatthew Dillon 	}
467d3313941SMatthew Dillon 
468d95d5e03SMatthew Dillon 	if ((ve = vkernel_find_vmspace(vkp, uap->id, 0)) == NULL) {
469d95d5e03SMatthew Dillon 		error = ENOENT;
470d95d5e03SMatthew Dillon 		goto done3;
471d95d5e03SMatthew Dillon 	}
472af2b4857SMatthew Dillon 
473af2b4857SMatthew Dillon 	/*
474d3313941SMatthew Dillon 	 * This code is basically copied from sys_mcontrol()
475d3313941SMatthew Dillon 	 */
4763919ced0SMatthew Dillon 	if (uap->behav < 0 || uap->behav > MADV_CONTROL_END) {
4773919ced0SMatthew Dillon 		error = EINVAL;
478af2b4857SMatthew Dillon 		goto done1;
4793919ced0SMatthew Dillon 	}
480d3313941SMatthew Dillon 
4813919ced0SMatthew Dillon 	if (tmpaddr < (vm_offset_t)uap->addr) {
4823919ced0SMatthew Dillon 		error = EINVAL;
483af2b4857SMatthew Dillon 		goto done1;
4843919ced0SMatthew Dillon 	}
4853919ced0SMatthew Dillon 	if (VM_MAX_USER_ADDRESS > 0 && tmpaddr > VM_MAX_USER_ADDRESS) {
4863919ced0SMatthew Dillon 		error = EINVAL;
487af2b4857SMatthew Dillon 		goto done1;
4883919ced0SMatthew Dillon 	}
4893919ced0SMatthew Dillon         if (VM_MIN_USER_ADDRESS > 0 && uap->addr < VM_MIN_USER_ADDRESS) {
4903919ced0SMatthew Dillon 		error = EINVAL;
491af2b4857SMatthew Dillon 		goto done1;
4923919ced0SMatthew Dillon 	}
493d3313941SMatthew Dillon 
494d3313941SMatthew Dillon 	start = trunc_page((vm_offset_t) uap->addr);
495e54488bbSMatthew Dillon 	end = round_page(tmpaddr);
496d3313941SMatthew Dillon 
4973919ced0SMatthew Dillon 	error = vm_map_madvise(&ve->vmspace->vm_map, start, end,
4983919ced0SMatthew Dillon 				uap->behav, uap->value);
499af2b4857SMatthew Dillon done1:
500d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
501af2b4857SMatthew Dillon done3:
5023919ced0SMatthew Dillon 	return (error);
503133aabc4SMatthew Dillon }
504133aabc4SMatthew Dillon 
505133aabc4SMatthew Dillon /*
506d3313941SMatthew Dillon  * Red black tree functions
507133aabc4SMatthew Dillon  */
508d3313941SMatthew Dillon static int rb_vmspace_compare(struct vmspace_entry *, struct vmspace_entry *);
509d3313941SMatthew Dillon RB_GENERATE(vmspace_rb_tree, vmspace_entry, rb_entry, rb_vmspace_compare);
510d3313941SMatthew Dillon 
511af2b4857SMatthew Dillon /*
512af2b4857SMatthew Dillon  * a->start is address, and the only field has to be initialized.
513af2b4857SMatthew Dillon  * The caller must hold vkp->token.
514af2b4857SMatthew Dillon  *
515af2b4857SMatthew Dillon  * The caller must hold vkp->token.
516af2b4857SMatthew Dillon  */
517d3313941SMatthew Dillon static int
rb_vmspace_compare(struct vmspace_entry * a,struct vmspace_entry * b)518d3313941SMatthew Dillon rb_vmspace_compare(struct vmspace_entry *a, struct vmspace_entry *b)
519133aabc4SMatthew Dillon {
520d3313941SMatthew Dillon         if ((char *)a->id < (char *)b->id)
521d3313941SMatthew Dillon                 return(-1);
522d3313941SMatthew Dillon         else if ((char *)a->id > (char *)b->id)
523d3313941SMatthew Dillon                 return(1);
524d3313941SMatthew Dillon         return(0);
525d3313941SMatthew Dillon }
526d3313941SMatthew Dillon 
527af2b4857SMatthew Dillon /*
528af2b4857SMatthew Dillon  * The caller must hold vkp->token.
529af2b4857SMatthew Dillon  */
530d3313941SMatthew Dillon static
531d3313941SMatthew Dillon int
rb_vmspace_delete(struct vmspace_entry * ve,void * data)532d3313941SMatthew Dillon rb_vmspace_delete(struct vmspace_entry *ve, void *data)
533d3313941SMatthew Dillon {
53439005e16SMatthew Dillon 	struct vkernel_proc *vkp = data;
535d3313941SMatthew Dillon 
5361e0d343fSMatthew Dillon 	if (vmspace_entry_delete(ve, vkp, 0) == 0)
5371e0d343fSMatthew Dillon 		vmspace_entry_cache_drop(ve);
5381e0d343fSMatthew Dillon 	else
53976f1911eSMatthew Dillon 		panic("rb_vmspace_delete: invalid refs %d", ve->refs);
540d3313941SMatthew Dillon 	return(0);
541d3313941SMatthew Dillon }
542d3313941SMatthew Dillon 
5434a22e893SMatthew Dillon /*
5444a22e893SMatthew Dillon  * Remove a vmspace_entry from the RB tree and destroy it.  We have to clean
5451e0d343fSMatthew Dillon  * up the pmap, the vm_map, then destroy the vmspace.  We gain control of
5461e0d343fSMatthew Dillon  * the associated cache_refs ref, which the caller will drop for us.
547af2b4857SMatthew Dillon  *
54876f1911eSMatthew Dillon  * The ve must not have any active references other than those from the
5491e0d343fSMatthew Dillon  * caller.  If it does, EBUSY is returned.  The ve may still maintain
5501e0d343fSMatthew Dillon  * any number of cache references which will drop as the related LWPs
5511e0d343fSMatthew Dillon  * execute vmspace operations or exit.
55276f1911eSMatthew Dillon  *
5531e0d343fSMatthew Dillon  * 0 is returned on success, EBUSY on failure.  On success the caller must
5541e0d343fSMatthew Dillon  * drop the last cache_refs.  We have dropped the callers active refs.
555af2b4857SMatthew Dillon  *
556af2b4857SMatthew Dillon  * The caller must hold vkp->token.
5574a22e893SMatthew Dillon  */
5584a22e893SMatthew Dillon static
55976f1911eSMatthew Dillon int
vmspace_entry_delete(struct vmspace_entry * ve,struct vkernel_proc * vkp,int refs)56076f1911eSMatthew Dillon vmspace_entry_delete(struct vmspace_entry *ve, struct vkernel_proc *vkp,
56176f1911eSMatthew Dillon 		     int refs)
5624a22e893SMatthew Dillon {
5631e0d343fSMatthew Dillon 	/*
5641e0d343fSMatthew Dillon 	 * Interlocked by vkp->token.
5651e0d343fSMatthew Dillon 	 *
5661e0d343fSMatthew Dillon 	 * Drop the callers refs and set VKE_REF_DELETED atomically, if
5671e0d343fSMatthew Dillon 	 * the remaining refs match exactly.  Dropping refs and setting
5681e0d343fSMatthew Dillon 	 * the DELETED flag atomically protects other threads from trying
5691e0d343fSMatthew Dillon 	 * to use the ve.
5701e0d343fSMatthew Dillon 	 *
5711e0d343fSMatthew Dillon 	 * The caller now owns the final cache_ref that was previously
5721e0d343fSMatthew Dillon 	 * associated with the live state of the ve.
5731e0d343fSMatthew Dillon 	 */
5741e0d343fSMatthew Dillon 	if (atomic_cmpset_int(&ve->refs, refs, VKE_REF_DELETED) == 0) {
5751e0d343fSMatthew Dillon 		KKASSERT(ve->refs >= refs);
5761e0d343fSMatthew Dillon 		return EBUSY;
57707511847SMatthew Dillon 	}
57839005e16SMatthew Dillon 	RB_REMOVE(vmspace_rb_tree, &vkp->root, ve);
5794a22e893SMatthew Dillon 
5804a22e893SMatthew Dillon 	pmap_remove_pages(vmspace_pmap(ve->vmspace),
58188181b08SMatthew Dillon 			  VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
5824a22e893SMatthew Dillon 	vm_map_remove(&ve->vmspace->vm_map,
58388181b08SMatthew Dillon 			  VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
58493f86408SMatthew Dillon 	vmspace_rel(ve->vmspace);
585a2ee730dSMatthew Dillon 	ve->vmspace = NULL; /* safety */
58698e80c61SMatthew Dillon 
5871e0d343fSMatthew Dillon 	return 0;
588d95d5e03SMatthew Dillon }
589d95d5e03SMatthew Dillon 
59076f1911eSMatthew Dillon /*
59176f1911eSMatthew Dillon  * Ref a ve for cache purposes
59276f1911eSMatthew Dillon  */
59376f1911eSMatthew Dillon static
59476f1911eSMatthew Dillon void
vmspace_entry_cache_ref(struct vmspace_entry * ve)59576f1911eSMatthew Dillon vmspace_entry_cache_ref(struct vmspace_entry *ve)
59676f1911eSMatthew Dillon {
59776f1911eSMatthew Dillon 	atomic_add_int(&ve->cache_refs, 1);
59876f1911eSMatthew Dillon }
59976f1911eSMatthew Dillon 
60076f1911eSMatthew Dillon /*
6011e0d343fSMatthew Dillon  * The ve cache_drop is the final word for a ve.  It gains an extra ref
6021e0d343fSMatthew Dillon  * representing it being on the RB tree and not being in a deleted state.
6031e0d343fSMatthew Dillon  * Removal from the RB tree and deletion manipulate this ref.  The last
6041e0d343fSMatthew Dillon  * drop will thus include full deletion of the ve in addition to the last
6051e0d343fSMatthew Dillon  * cached user going away.
60676f1911eSMatthew Dillon  */
60776f1911eSMatthew Dillon static
60876f1911eSMatthew Dillon void
vmspace_entry_cache_drop(struct vmspace_entry * ve)60976f1911eSMatthew Dillon vmspace_entry_cache_drop(struct vmspace_entry *ve)
61076f1911eSMatthew Dillon {
61176f1911eSMatthew Dillon 	if (atomic_fetchadd_int(&ve->cache_refs, -1) == 1) {
6121e0d343fSMatthew Dillon 		KKASSERT(ve->refs & VKE_REF_DELETED);
61376f1911eSMatthew Dillon 		kfree(ve, M_VKERNEL);
61476f1911eSMatthew Dillon 	}
61576f1911eSMatthew Dillon }
61676f1911eSMatthew Dillon 
61776f1911eSMatthew Dillon /*
61876f1911eSMatthew Dillon  * Drop primary reference.  The ve cannot be freed on the 1->0 transition.
61976f1911eSMatthew Dillon  * Instead, ve deletion interlocks the final kfree() via cache_refs.
62076f1911eSMatthew Dillon  */
621d95d5e03SMatthew Dillon static
622d95d5e03SMatthew Dillon void
vmspace_entry_drop(struct vmspace_entry * ve)623d95d5e03SMatthew Dillon vmspace_entry_drop(struct vmspace_entry *ve)
624d95d5e03SMatthew Dillon {
62576f1911eSMatthew Dillon 	atomic_fetchadd_int(&ve->refs, -1);
6264a22e893SMatthew Dillon }
6274a22e893SMatthew Dillon 
628af2b4857SMatthew Dillon /*
629af2b4857SMatthew Dillon  * Locate the ve for (id), return the ve or NULL.  If found this function
630af2b4857SMatthew Dillon  * will bump ve->refs which prevents the ve from being immediately destroyed
631af2b4857SMatthew Dillon  * (but it can still be removed).
632af2b4857SMatthew Dillon  *
633d95d5e03SMatthew Dillon  * The cache can potentially contain a stale ve, check by testing ve->vmspace.
634d95d5e03SMatthew Dillon  *
635d95d5e03SMatthew Dillon  * The caller must hold vkp->token if excl is non-zero.
636af2b4857SMatthew Dillon  */
637d3313941SMatthew Dillon static
638d3313941SMatthew Dillon struct vmspace_entry *
vkernel_find_vmspace(struct vkernel_proc * vkp,void * id,int excl)639d95d5e03SMatthew Dillon vkernel_find_vmspace(struct vkernel_proc *vkp, void *id, int excl)
640d3313941SMatthew Dillon {
641d3313941SMatthew Dillon 	struct vmspace_entry *ve;
642d3313941SMatthew Dillon 	struct vmspace_entry key;
643d95d5e03SMatthew Dillon 	struct vkernel_lwp *vklp;
644d95d5e03SMatthew Dillon 	struct lwp *lp = curthread->td_lwp;
645d3313941SMatthew Dillon 
64676f1911eSMatthew Dillon 	/*
64776f1911eSMatthew Dillon 	 * Cache check.  Since we already hold a ref on the cache entry
64876f1911eSMatthew Dillon 	 * the ve cannot be ripped out from under us while we cycle
64976f1911eSMatthew Dillon 	 * ve->refs.
65076f1911eSMatthew Dillon 	 */
651d95d5e03SMatthew Dillon 	if ((vklp = lp->lwp_vkernel) != NULL) {
652d95d5e03SMatthew Dillon 		ve = vklp->ve_cache;
65376f1911eSMatthew Dillon 		if (ve && ve->id == id) {
65476f1911eSMatthew Dillon 			uint32_t n;
65576f1911eSMatthew Dillon 
65676f1911eSMatthew Dillon 			/*
65776f1911eSMatthew Dillon 			 * Bump active refs, check to see if the cache
65876f1911eSMatthew Dillon 			 * entry is stale.  If not, we are good.
65976f1911eSMatthew Dillon 			 */
66076f1911eSMatthew Dillon 			n = atomic_fetchadd_int(&ve->refs, 1);
66176f1911eSMatthew Dillon 			if ((n & VKE_REF_DELETED) == 0) {
66276f1911eSMatthew Dillon 				KKASSERT(ve->vmspace);
66376f1911eSMatthew Dillon 				return ve;
664d95d5e03SMatthew Dillon 			}
66576f1911eSMatthew Dillon 
66676f1911eSMatthew Dillon 			/*
66776f1911eSMatthew Dillon 			 * Cache is stale, clean it out and fall through
66876f1911eSMatthew Dillon 			 * to a normal search.
66976f1911eSMatthew Dillon 			 */
67076f1911eSMatthew Dillon 			vklp->ve_cache = NULL;
67176f1911eSMatthew Dillon 			vmspace_entry_drop(ve);
67276f1911eSMatthew Dillon 			vmspace_entry_cache_drop(ve);
67376f1911eSMatthew Dillon 		}
67476f1911eSMatthew Dillon 	}
67576f1911eSMatthew Dillon 
67676f1911eSMatthew Dillon 	/*
67776f1911eSMatthew Dillon 	 * Normal search protected by vkp->token.  No new ve's can be marked
67876f1911eSMatthew Dillon 	 * DELETED while we hold the token so we are safe.
67976f1911eSMatthew Dillon 	 */
680d95d5e03SMatthew Dillon 	if (excl == 0)
681d95d5e03SMatthew Dillon 		lwkt_gettoken_shared(&vkp->token);
682d3313941SMatthew Dillon 	key.id = id;
68339005e16SMatthew Dillon 	ve = RB_FIND(vmspace_rb_tree, &vkp->root, &key);
684d95d5e03SMatthew Dillon 	if (ve) {
68576f1911eSMatthew Dillon 		if (atomic_fetchadd_int(&ve->refs, 1) & VKE_REF_DELETED) {
68676f1911eSMatthew Dillon 			vmspace_entry_drop(ve);
687d95d5e03SMatthew Dillon 			ve = NULL;
688d95d5e03SMatthew Dillon 		}
68976f1911eSMatthew Dillon 	}
690d95d5e03SMatthew Dillon 	if (excl == 0)
691d95d5e03SMatthew Dillon 		lwkt_reltoken(&vkp->token);
692d3313941SMatthew Dillon 	return (ve);
693d3313941SMatthew Dillon }
694d3313941SMatthew Dillon 
695d3313941SMatthew Dillon /*
696d3313941SMatthew Dillon  * Manage vkernel refs, used by the kernel when fork()ing or exit()ing
697d3313941SMatthew Dillon  * a vkernel process.
698af2b4857SMatthew Dillon  *
699af2b4857SMatthew Dillon  * No requirements.
700d3313941SMatthew Dillon  */
701d3313941SMatthew Dillon void
vkernel_inherit(struct proc * p1,struct proc * p2)7024a22e893SMatthew Dillon vkernel_inherit(struct proc *p1, struct proc *p2)
703d3313941SMatthew Dillon {
70439005e16SMatthew Dillon 	struct vkernel_proc *vkp;
7054a22e893SMatthew Dillon 
70639005e16SMatthew Dillon 	vkp = p1->p_vkernel;
70739005e16SMatthew Dillon 	KKASSERT(vkp->refs > 0);
70839005e16SMatthew Dillon 	atomic_add_int(&vkp->refs, 1);
70939005e16SMatthew Dillon 	p2->p_vkernel = vkp;
710d3313941SMatthew Dillon }
711d3313941SMatthew Dillon 
712af2b4857SMatthew Dillon /*
713af2b4857SMatthew Dillon  * No requirements.
714af2b4857SMatthew Dillon  */
715d3313941SMatthew Dillon void
vkernel_exit(struct proc * p)7164a22e893SMatthew Dillon vkernel_exit(struct proc *p)
717d3313941SMatthew Dillon {
71839005e16SMatthew Dillon 	struct vkernel_proc *vkp;
719287ebb09SMatthew Dillon 	struct lwp *lp;
7204a22e893SMatthew Dillon 
72139005e16SMatthew Dillon 	vkp = p->p_vkernel;
722af2b4857SMatthew Dillon 
7234a22e893SMatthew Dillon 	/*
7244a22e893SMatthew Dillon 	 * Restore the original VM context if we are killed while running
7254a22e893SMatthew Dillon 	 * a different one.
7264e7c41c5SMatthew Dillon 	 *
7274e7c41c5SMatthew Dillon 	 * This isn't supposed to happen.  What is supposed to happen is
7284e7c41c5SMatthew Dillon 	 * that the process should enter vkernel_trap() before the handling
7294e7c41c5SMatthew Dillon 	 * the signal.
7304a22e893SMatthew Dillon 	 */
7313e291793SMatthew Dillon 	RB_FOREACH(lp, lwp_rb_tree, &p->p_lwp_tree) {
73239005e16SMatthew Dillon 		vkernel_lwp_exit(lp);
733287ebb09SMatthew Dillon 	}
7344a22e893SMatthew Dillon 
7354a22e893SMatthew Dillon 	/*
7364a22e893SMatthew Dillon 	 * Dereference the common area
7374a22e893SMatthew Dillon 	 */
73839005e16SMatthew Dillon 	p->p_vkernel = NULL;
73939005e16SMatthew Dillon 	KKASSERT(vkp->refs > 0);
7404a22e893SMatthew Dillon 
741af2b4857SMatthew Dillon 	if (atomic_fetchadd_int(&vkp->refs, -1) == 1) {
742af2b4857SMatthew Dillon 		lwkt_gettoken(&vkp->token);
74339005e16SMatthew Dillon 		RB_SCAN(vmspace_rb_tree, &vkp->root, NULL,
74439005e16SMatthew Dillon 			rb_vmspace_delete, vkp);
745af2b4857SMatthew Dillon 		lwkt_reltoken(&vkp->token);
74639005e16SMatthew Dillon 		kfree(vkp, M_VKERNEL);
7474a22e893SMatthew Dillon 	}
74839005e16SMatthew Dillon }
74939005e16SMatthew Dillon 
750af2b4857SMatthew Dillon /*
751af2b4857SMatthew Dillon  * No requirements.
752af2b4857SMatthew Dillon  */
75339005e16SMatthew Dillon void
vkernel_lwp_exit(struct lwp * lp)75439005e16SMatthew Dillon vkernel_lwp_exit(struct lwp *lp)
75539005e16SMatthew Dillon {
75639005e16SMatthew Dillon 	struct vkernel_lwp *vklp;
75739005e16SMatthew Dillon 	struct vmspace_entry *ve;
75839005e16SMatthew Dillon 
75939005e16SMatthew Dillon 	if ((vklp = lp->lwp_vkernel) != NULL) {
760e1ea8b24SMatthew Dillon 		/*
761e1ea8b24SMatthew Dillon 		 * vkernel thread
762e1ea8b24SMatthew Dillon 		 */
76339005e16SMatthew Dillon 		if ((ve = vklp->ve) != NULL) {
76439005e16SMatthew Dillon 			kprintf("Warning, pid %d killed with "
76539005e16SMatthew Dillon 			    "active VC!\n", lp->lwp_proc->p_pid);
76639005e16SMatthew Dillon 			pmap_setlwpvm(lp, lp->lwp_proc->p_vmspace);
76739005e16SMatthew Dillon 			vklp->ve = NULL;
76839005e16SMatthew Dillon 			KKASSERT(ve->refs > 0);
769d95d5e03SMatthew Dillon 			vmspace_entry_drop(ve);
77039005e16SMatthew Dillon 		}
771d95d5e03SMatthew Dillon 		if ((ve = vklp->ve_cache) != NULL) {
772d95d5e03SMatthew Dillon 			vklp->ve_cache = NULL;
77376f1911eSMatthew Dillon 			vmspace_entry_cache_drop(ve);
774d95d5e03SMatthew Dillon 		}
775d95d5e03SMatthew Dillon 
77639005e16SMatthew Dillon 		lp->lwp_vkernel = NULL;
77739005e16SMatthew Dillon 		kfree(vklp, M_VKERNEL);
77839005e16SMatthew Dillon 	}
779d3313941SMatthew Dillon }
7804a22e893SMatthew Dillon 
7814a22e893SMatthew Dillon /*
7824a22e893SMatthew Dillon  * A VM space under virtual kernel control trapped out or made a system call
7834a22e893SMatthew Dillon  * or otherwise needs to return control to the virtual kernel context.
784af2b4857SMatthew Dillon  *
785af2b4857SMatthew Dillon  * No requirements.
7864a22e893SMatthew Dillon  */
787bb47c072SMatthew Dillon void
vkernel_trap(struct lwp * lp,struct trapframe * frame)788287ebb09SMatthew Dillon vkernel_trap(struct lwp *lp, struct trapframe *frame)
7894a22e893SMatthew Dillon {
790287ebb09SMatthew Dillon 	struct proc *p = lp->lwp_proc;
7914a22e893SMatthew Dillon 	struct vmspace_entry *ve;
79239005e16SMatthew Dillon 	struct vkernel_lwp *vklp;
7934a22e893SMatthew Dillon 	int error;
7944a22e893SMatthew Dillon 
7954a22e893SMatthew Dillon 	/*
7964a22e893SMatthew Dillon 	 * Which vmspace entry was running?
7974a22e893SMatthew Dillon 	 */
79839005e16SMatthew Dillon 	vklp = lp->lwp_vkernel;
79939005e16SMatthew Dillon 	KKASSERT(vklp);
800a86ce0cdSMatthew Dillon 
80139005e16SMatthew Dillon 	ve = vklp->ve;
8024a22e893SMatthew Dillon 	KKASSERT(ve != NULL);
8034a22e893SMatthew Dillon 
8044a22e893SMatthew Dillon 	/*
805287ebb09SMatthew Dillon 	 * Switch the LWP vmspace back to the virtual kernel's VM space.
8064a22e893SMatthew Dillon 	 */
80739005e16SMatthew Dillon 	vklp->ve = NULL;
808287ebb09SMatthew Dillon 	pmap_setlwpvm(lp, p->p_vmspace);
8094a22e893SMatthew Dillon 	KKASSERT(ve->refs > 0);
810d95d5e03SMatthew Dillon 	vmspace_entry_drop(ve);
811af2b4857SMatthew Dillon 	/* ve is invalid once we kill our ref */
812e1ea8b24SMatthew Dillon 
8134a22e893SMatthew Dillon 	/*
8144e7c41c5SMatthew Dillon 	 * Copy the emulated process frame to the virtual kernel process.
8154e7c41c5SMatthew Dillon 	 * The emulated process cannot change TLS descriptors so don't
8164e7c41c5SMatthew Dillon 	 * bother saving them, we already have a copy.
8174e7c41c5SMatthew Dillon 	 *
8184e7c41c5SMatthew Dillon 	 * Restore the virtual kernel's saved context so the virtual kernel
8194e7c41c5SMatthew Dillon 	 * process can resume.
8204a22e893SMatthew Dillon 	 */
82139005e16SMatthew Dillon 	error = copyout(frame, vklp->user_trapframe, sizeof(*frame));
82239005e16SMatthew Dillon 	bcopy(&vklp->save_trapframe, frame, sizeof(*frame));
82339005e16SMatthew Dillon 	bcopy(&vklp->save_vextframe.vx_tls, &curthread->td_tls,
82439005e16SMatthew Dillon 	      sizeof(vklp->save_vextframe.vx_tls));
8254e7c41c5SMatthew Dillon 	set_user_TLS();
826bb47c072SMatthew Dillon 	cpu_vkernel_trap(frame, error);
827133aabc4SMatthew Dillon }
828