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