kernel - Major SMP performance patch / VM system, bus-fault/seg-fault fixes
[dragonfly.git] / sys / vm / vm_vmspace.c
1 /*
2  * (MPSAFE)
3  *
4  * Copyright (c) 2006 The DragonFly Project.  All rights reserved.
5  * 
6  * This code is derived from software contributed to The DragonFly Project
7  * by Matthew Dillon <dillon@backplane.com>
8  * 
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in
17  *    the documentation and/or other materials provided with the
18  *    distribution.
19  * 3. Neither the name of The DragonFly Project nor the names of its
20  *    contributors may be used to endorse or promote products derived
21  *    from this software without specific, prior written permission.
22  * 
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
29  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
30  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
31  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
32  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
33  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  */
36
37 #include <sys/param.h>
38 #include <sys/kernel.h>
39 #include <sys/systm.h>
40 #include <sys/sysproto.h>
41 #include <sys/kern_syscall.h>
42 #include <sys/mman.h>
43 #include <sys/thread.h>
44 #include <sys/proc.h>
45 #include <sys/malloc.h>
46 #include <sys/sysctl.h>
47 #include <sys/vkernel.h>
48 #include <sys/vmspace.h>
49
50 #include <vm/vm_extern.h>
51 #include <vm/pmap.h>
52
53 #include <machine/vmparam.h>
54
55 #include <sys/sysref2.h>
56 #include <sys/mplock2.h>
57
58 static struct vmspace_entry *vkernel_find_vmspace(struct vkernel_proc *vkp,
59                                                   void *id);
60 static void vmspace_entry_delete(struct vmspace_entry *ve,
61                                  struct vkernel_proc *vkp);
62
63 static MALLOC_DEFINE(M_VKERNEL, "vkernel", "VKernel structures");
64
65 /*
66  * vmspace_create (void *id, int type, void *data)
67  *
68  * Create a VMSPACE under the control of the caller with the specified id.
69  * An id of NULL cannot be used.  The type and data fields must currently
70  * be 0.
71  *
72  * The vmspace starts out completely empty.  Memory may be mapped into the
73  * VMSPACE with vmspace_mmap() and MAP_VPAGETABLE section(s) controlled
74  * with vmspace_mcontrol().
75  *
76  * No requirements.
77  */
78 int
79 sys_vmspace_create(struct vmspace_create_args *uap)
80 {
81         struct vmspace_entry *ve;
82         struct vkernel_proc *vkp;
83         struct proc *p = curproc;
84         int error;
85
86         if (vkernel_enable == 0)
87                 return (EOPNOTSUPP);
88
89         /*
90          * Create a virtual kernel side-structure for the process if one
91          * does not exist.
92          *
93          * Implement a simple resolution for SMP races.
94          */
95         if ((vkp = p->p_vkernel) == NULL) {
96                 vkp = kmalloc(sizeof(*vkp), M_VKERNEL, M_WAITOK|M_ZERO);
97                 lwkt_gettoken(&proc_token);
98                 if (p->p_vkernel == NULL) {
99                         vkp->refs = 1;
100                         lwkt_token_init(&vkp->token, "vkernel");
101                         RB_INIT(&vkp->root);
102                         p->p_vkernel = vkp;
103                 } else {
104                         kfree(vkp, M_VKERNEL);
105                         vkp = p->p_vkernel;
106                 }
107                 lwkt_reltoken(&proc_token);
108         }
109
110         get_mplock();
111
112         /*
113          * Create a new VMSPACE, disallow conflicting ids
114          */
115         ve = kmalloc(sizeof(struct vmspace_entry), M_VKERNEL, M_WAITOK|M_ZERO);
116         ve->vmspace = vmspace_alloc(VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
117         ve->id = uap->id;
118         pmap_pinit2(vmspace_pmap(ve->vmspace));
119
120         lwkt_gettoken(&vkp->token);
121         if (RB_INSERT(vmspace_rb_tree, &vkp->root, ve)) {
122                 sysref_put(&ve->vmspace->vm_sysref);
123                 kfree(ve, M_VKERNEL);
124                 error = EEXIST;
125         } else {
126                 error = 0;
127         }
128         lwkt_reltoken(&vkp->token);
129         rel_mplock();
130         return (error);
131 }
132
133 /*
134  * Destroy a VMSPACE given its identifier.
135  *
136  * No requirements.
137  */
138 int
139 sys_vmspace_destroy(struct vmspace_destroy_args *uap)
140 {
141         struct vkernel_proc *vkp;
142         struct vmspace_entry *ve;
143         int error;
144
145         get_mplock();
146         if ((vkp = curproc->p_vkernel) == NULL) {
147                 error = EINVAL;
148                 goto done3;
149         }
150         lwkt_gettoken(&vkp->token);
151         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
152                 error = ENOENT;
153                 goto done2;
154         }
155         if (ve->refs) {
156                 error = EBUSY;
157                 goto done2;
158         }
159         vmspace_entry_delete(ve, vkp);
160         error = 0;
161 done2:
162         lwkt_reltoken(&vkp->token);
163 done3:
164         rel_mplock();
165         return(error);
166 }
167
168 /*
169  * vmspace_ctl (void *id, int cmd, struct trapframe *tframe,
170  *              struct vextframe *vframe);
171  *
172  * Transfer control to a VMSPACE.  Control is returned after the specified
173  * number of microseconds or if a page fault, signal, trap, or system call
174  * occurs.  The context is updated as appropriate.
175  *
176  * No requirements.
177  */
178 int
179 sys_vmspace_ctl(struct vmspace_ctl_args *uap)
180 {
181         struct vkernel_proc *vkp;
182         struct vkernel_lwp *vklp;
183         struct vmspace_entry *ve;
184         struct lwp *lp;
185         struct proc *p;
186         int framesz;
187         int error;
188
189         lp = curthread->td_lwp;
190         p = lp->lwp_proc;
191
192         if ((vkp = p->p_vkernel) == NULL)
193                 return (EINVAL);
194
195         get_mplock();
196         lwkt_gettoken(&vkp->token);
197         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
198                 error = ENOENT;
199                 goto done;
200         }
201
202         /*
203          * Signal mailbox interlock
204          */
205         if (p->p_flag & P_MAILBOX) {
206                 p->p_flag &= ~P_MAILBOX;
207                 error = EINTR;
208                 goto done;
209         }
210
211         switch(uap->cmd) {
212         case VMSPACE_CTL_RUN:
213                 /*
214                  * Save the caller's register context, swap VM spaces, and
215                  * install the passed register context.  Return with
216                  * EJUSTRETURN so the syscall code doesn't adjust the context.
217                  */
218                 atomic_add_int(&ve->refs, 1);
219                 framesz = sizeof(struct trapframe);
220                 if ((vklp = lp->lwp_vkernel) == NULL) {
221                         vklp = kmalloc(sizeof(*vklp), M_VKERNEL,
222                                        M_WAITOK|M_ZERO);
223                         lp->lwp_vkernel = vklp;
224                 }
225                 vklp->user_trapframe = uap->tframe;
226                 vklp->user_vextframe = uap->vframe;
227                 bcopy(uap->sysmsg_frame, &vklp->save_trapframe, framesz);
228                 bcopy(&curthread->td_tls, &vklp->save_vextframe.vx_tls,
229                       sizeof(vklp->save_vextframe.vx_tls));
230                 error = copyin(uap->tframe, uap->sysmsg_frame, framesz);
231                 if (error == 0) {
232                         error = copyin(&uap->vframe->vx_tls,
233                                        &curthread->td_tls,
234                                        sizeof(struct savetls));
235                 }
236                 if (error == 0)
237                         error = cpu_sanitize_frame(uap->sysmsg_frame);
238                 if (error == 0)
239                         error = cpu_sanitize_tls(&curthread->td_tls);
240                 if (error) {
241                         bcopy(&vklp->save_trapframe, uap->sysmsg_frame,
242                               framesz);
243                         bcopy(&vklp->save_vextframe.vx_tls, &curthread->td_tls,
244                               sizeof(vklp->save_vextframe.vx_tls));
245                         set_user_TLS();
246                         atomic_subtract_int(&ve->refs, 1);
247                 } else {
248                         vklp->ve = ve;
249                         pmap_setlwpvm(lp, ve->vmspace);
250                         set_user_TLS();
251                         set_vkernel_fp(uap->sysmsg_frame);
252                         error = EJUSTRETURN;
253                 }
254                 break;
255         default:
256                 error = EOPNOTSUPP;
257                 break;
258         }
259 done:
260         lwkt_reltoken(&vkp->token);
261         rel_mplock();
262         return(error);
263 }
264
265 /*
266  * vmspace_mmap(id, addr, len, prot, flags, fd, offset)
267  *
268  * map memory within a VMSPACE.  This function is just like a normal mmap()
269  * but operates on the vmspace's memory map.  Most callers use this to create
270  * a MAP_VPAGETABLE mapping.
271  *
272  * No requirements.
273  */
274 int
275 sys_vmspace_mmap(struct vmspace_mmap_args *uap)
276 {
277         struct vkernel_proc *vkp;
278         struct vmspace_entry *ve;
279         int error;
280
281         /*
282          * We hold the vmspace token to serialize calls to vkernel_find_vmspace.
283          */
284         lwkt_gettoken(&vmspace_token);
285         if ((vkp = curproc->p_vkernel) == NULL) {
286                 error = EINVAL;
287                 goto done3;
288         }
289
290         /*
291          * NOTE: kern_mmap() can block so we need to temporarily ref ve->refs.
292          */
293         lwkt_gettoken(&vkp->token);
294         if ((ve = vkernel_find_vmspace(vkp, uap->id)) != NULL) {
295                 atomic_add_int(&ve->refs, 1);
296                 error = kern_mmap(ve->vmspace, uap->addr, uap->len,
297                                   uap->prot, uap->flags,
298                                   uap->fd, uap->offset, &uap->sysmsg_resultp);
299                 atomic_subtract_int(&ve->refs, 1);
300         } else {
301                 error = ENOENT;
302         }
303         lwkt_reltoken(&vkp->token);
304 done3:
305         lwkt_reltoken(&vmspace_token);
306         return (error);
307 }
308
309 /*
310  * vmspace_munmap(id, addr, len)
311  *
312  * unmap memory within a VMSPACE.
313  *
314  * No requirements.
315  */
316 int
317 sys_vmspace_munmap(struct vmspace_munmap_args *uap)
318 {
319         struct vkernel_proc *vkp;
320         struct vmspace_entry *ve;
321         vm_offset_t addr;
322         vm_offset_t tmpaddr;
323         vm_size_t size, pageoff;
324         vm_map_t map;
325         int error;
326
327         get_mplock();
328         if ((vkp = curproc->p_vkernel) == NULL) {
329                 error = EINVAL;
330                 goto done3;
331         }
332         lwkt_gettoken(&vkp->token);
333         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
334                 error = ENOENT;
335                 goto done2;
336         }
337
338         /*
339          * NOTE: kern_munmap() can block so we need to temporarily
340          *       ref ve->refs.
341          */
342         atomic_add_int(&ve->refs, 1);
343
344         /*
345          * Copied from sys_munmap()
346          */
347         addr = (vm_offset_t)uap->addr;
348         size = uap->len;
349
350         pageoff = (addr & PAGE_MASK);
351         addr -= pageoff;
352         size += pageoff;
353         size = (vm_size_t)round_page(size);
354         if (size < uap->len) {          /* wrap */
355                 error = EINVAL;
356                 goto done1;
357         }
358         tmpaddr = addr + size;          /* workaround gcc4 opt */
359         if (tmpaddr < addr) {           /* wrap */
360                 error = EINVAL;
361                 goto done1;
362         }
363         if (size == 0) {
364                 error = 0;
365                 goto done1;
366         }
367
368         if (VM_MAX_USER_ADDRESS > 0 && tmpaddr > VM_MAX_USER_ADDRESS) {
369                 error = EINVAL;
370                 goto done1;
371         }
372         if (VM_MIN_USER_ADDRESS > 0 && addr < VM_MIN_USER_ADDRESS) {
373                 error = EINVAL;
374                 goto done1;
375         }
376         map = &ve->vmspace->vm_map;
377         if (!vm_map_check_protection(map, addr, tmpaddr, VM_PROT_NONE, FALSE)) {
378                 error = EINVAL;
379                 goto done1;
380         }
381         vm_map_remove(map, addr, addr + size);
382         error = 0;
383 done1:
384         atomic_subtract_int(&ve->refs, 1);
385 done2:
386         lwkt_reltoken(&vkp->token);
387 done3:
388         rel_mplock();
389         return (error);
390 }
391
392 /* 
393  * vmspace_pread(id, buf, nbyte, flags, offset)
394  *
395  * Read data from a vmspace.  The number of bytes read is returned or
396  * -1 if an unrecoverable error occured.  If the number of bytes read is
397  * less then the request size, a page fault occured in the VMSPACE which
398  * the caller must resolve in order to proceed.
399  *
400  * (not implemented yet)
401  * No requirements.
402  */
403 int
404 sys_vmspace_pread(struct vmspace_pread_args *uap)
405 {
406         struct vkernel_proc *vkp;
407         struct vmspace_entry *ve;
408         int error;
409
410         get_mplock();
411         if ((vkp = curproc->p_vkernel) == NULL) {
412                 error = EINVAL;
413                 goto done3;
414         }
415         lwkt_gettoken(&vkp->token);
416         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
417                 error = ENOENT;
418                 goto done2;
419         }
420         error = EINVAL;
421 done2:
422         lwkt_reltoken(&vkp->token);
423 done3:
424         rel_mplock();
425         return (error);
426 }
427
428 /*
429  * vmspace_pwrite(id, buf, nbyte, flags, offset)
430  *
431  * Write data to a vmspace.  The number of bytes written is returned or
432  * -1 if an unrecoverable error occured.  If the number of bytes written is
433  * less then the request size, a page fault occured in the VMSPACE which
434  * the caller must resolve in order to proceed.
435  *
436  * (not implemented yet)
437  * No requirements.
438  */
439 int
440 sys_vmspace_pwrite(struct vmspace_pwrite_args *uap)
441 {
442         struct vkernel_proc *vkp;
443         struct vmspace_entry *ve;
444         int error;
445
446         get_mplock();
447         if ((vkp = curproc->p_vkernel) == NULL) {
448                 error = EINVAL;
449                 goto done3;
450         }
451         lwkt_gettoken(&vkp->token);
452         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
453                 error = ENOENT;
454                 goto done2;
455         }
456         error = EINVAL;
457 done2:
458         lwkt_reltoken(&vkp->token);
459 done3:
460         rel_mplock();
461         return (error);
462 }
463
464 /*
465  * vmspace_mcontrol(id, addr, len, behav, value)
466  *
467  * madvise/mcontrol support for a vmspace.
468  *
469  * No requirements.
470  */
471 int
472 sys_vmspace_mcontrol(struct vmspace_mcontrol_args *uap)
473 {
474         struct vkernel_proc *vkp;
475         struct vmspace_entry *ve;
476         vm_offset_t start, end;
477         vm_offset_t tmpaddr = (vm_offset_t)uap->addr + uap->len;
478         int error;
479
480         get_mplock();
481         if ((vkp = curproc->p_vkernel) == NULL) {
482                 error = EINVAL;
483                 goto done3;
484         }
485         lwkt_gettoken(&vkp->token);
486         if ((ve = vkernel_find_vmspace(vkp, uap->id)) == NULL) {
487                 error = ENOENT;
488                 goto done2;
489         }
490
491         /*
492          * NOTE: kern_madvise() can block so we need to temporarily
493          *       ref ve->refs.
494          */
495         atomic_add_int(&ve->refs, 1);
496
497         /*
498          * This code is basically copied from sys_mcontrol()
499          */
500         if (uap->behav < 0 || uap->behav > MADV_CONTROL_END) {
501                 error = EINVAL;
502                 goto done1;
503         }
504
505         if (tmpaddr < (vm_offset_t)uap->addr) {
506                 error = EINVAL;
507                 goto done1;
508         }
509         if (VM_MAX_USER_ADDRESS > 0 && tmpaddr > VM_MAX_USER_ADDRESS) {
510                 error = EINVAL;
511                 goto done1;
512         }
513         if (VM_MIN_USER_ADDRESS > 0 && uap->addr < VM_MIN_USER_ADDRESS) {
514                 error = EINVAL;
515                 goto done1;
516         }
517
518         start = trunc_page((vm_offset_t) uap->addr);
519         end = round_page(tmpaddr);
520
521         error = vm_map_madvise(&ve->vmspace->vm_map, start, end,
522                                 uap->behav, uap->value);
523 done1:
524         atomic_subtract_int(&ve->refs, 1);
525 done2:
526         lwkt_reltoken(&vkp->token);
527 done3:
528         rel_mplock();
529         return (error);
530 }
531
532 /*
533  * Red black tree functions
534  */
535 static int rb_vmspace_compare(struct vmspace_entry *, struct vmspace_entry *);
536 RB_GENERATE(vmspace_rb_tree, vmspace_entry, rb_entry, rb_vmspace_compare);
537    
538 /*
539  * a->start is address, and the only field has to be initialized.
540  * The caller must hold vkp->token.
541  *
542  * The caller must hold vkp->token.
543  */
544 static int
545 rb_vmspace_compare(struct vmspace_entry *a, struct vmspace_entry *b)
546 {
547         if ((char *)a->id < (char *)b->id)
548                 return(-1);
549         else if ((char *)a->id > (char *)b->id)
550                 return(1);
551         return(0);
552 }
553
554 /*
555  * The caller must hold vkp->token.
556  */
557 static
558 int
559 rb_vmspace_delete(struct vmspace_entry *ve, void *data)
560 {
561         struct vkernel_proc *vkp = data;
562
563         KKASSERT(ve->refs == 0);
564         vmspace_entry_delete(ve, vkp);
565         return(0);
566 }
567
568 /*
569  * Remove a vmspace_entry from the RB tree and destroy it.  We have to clean
570  * up the pmap, the vm_map, then destroy the vmspace.
571  *
572  * This function must remove the ve immediately before it might potentially
573  * block.
574  *
575  * The caller must hold vkp->token.
576  */
577 static
578 void
579 vmspace_entry_delete(struct vmspace_entry *ve, struct vkernel_proc *vkp)
580 {
581         RB_REMOVE(vmspace_rb_tree, &vkp->root, ve);
582
583         pmap_remove_pages(vmspace_pmap(ve->vmspace),
584                           VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
585         vm_map_remove(&ve->vmspace->vm_map,
586                       VM_MIN_USER_ADDRESS, VM_MAX_USER_ADDRESS);
587         sysref_put(&ve->vmspace->vm_sysref);
588         kfree(ve, M_VKERNEL);
589 }
590
591 /*
592  * Locate the ve for (id), return the ve or NULL.  If found this function
593  * will bump ve->refs which prevents the ve from being immediately destroyed
594  * (but it can still be removed).
595  *
596  * The caller must hold vkp->token.
597  */
598 static
599 struct vmspace_entry *
600 vkernel_find_vmspace(struct vkernel_proc *vkp, void *id)
601 {
602         struct vmspace_entry *ve;
603         struct vmspace_entry key;
604
605         key.id = id;
606         ve = RB_FIND(vmspace_rb_tree, &vkp->root, &key);
607         return (ve);
608 }
609
610 /*
611  * Manage vkernel refs, used by the kernel when fork()ing or exit()ing
612  * a vkernel process.
613  *
614  * No requirements.
615  */
616 void
617 vkernel_inherit(struct proc *p1, struct proc *p2)
618 {
619         struct vkernel_proc *vkp;
620
621         vkp = p1->p_vkernel;
622         KKASSERT(vkp->refs > 0);
623         atomic_add_int(&vkp->refs, 1);
624         p2->p_vkernel = vkp;
625 }
626
627 /*
628  * No requirements.
629  */
630 void
631 vkernel_exit(struct proc *p)
632 {
633         struct vkernel_proc *vkp;
634         struct lwp *lp;
635
636         vkp = p->p_vkernel;
637
638         /*
639          * Restore the original VM context if we are killed while running
640          * a different one.
641          *
642          * This isn't supposed to happen.  What is supposed to happen is
643          * that the process should enter vkernel_trap() before the handling
644          * the signal.
645          */
646         RB_FOREACH(lp, lwp_rb_tree, &p->p_lwp_tree) {
647                 vkernel_lwp_exit(lp);
648         }
649
650         /*
651          * Dereference the common area
652          */
653         p->p_vkernel = NULL;
654         KKASSERT(vkp->refs > 0);
655
656         if (atomic_fetchadd_int(&vkp->refs, -1) == 1) {
657                 lwkt_gettoken(&vkp->token);
658                 RB_SCAN(vmspace_rb_tree, &vkp->root, NULL,
659                         rb_vmspace_delete, vkp);
660                 lwkt_reltoken(&vkp->token);
661                 kfree(vkp, M_VKERNEL);
662         }
663 }
664
665 /*
666  * No requirements.
667  */
668 void
669 vkernel_lwp_exit(struct lwp *lp)
670 {
671         struct vkernel_lwp *vklp;
672         struct vmspace_entry *ve;
673
674         if ((vklp = lp->lwp_vkernel) != NULL) {
675                 if ((ve = vklp->ve) != NULL) {
676                         kprintf("Warning, pid %d killed with "
677                                 "active VC!\n", lp->lwp_proc->p_pid);
678                         pmap_setlwpvm(lp, lp->lwp_proc->p_vmspace);
679                         vklp->ve = NULL;
680                         KKASSERT(ve->refs > 0);
681                         atomic_subtract_int(&ve->refs, 1);
682                 }
683                 lp->lwp_vkernel = NULL;
684                 kfree(vklp, M_VKERNEL);
685         }
686 }
687
688 /*
689  * A VM space under virtual kernel control trapped out or made a system call
690  * or otherwise needs to return control to the virtual kernel context.
691  *
692  * No requirements.
693  */
694 void
695 vkernel_trap(struct lwp *lp, struct trapframe *frame)
696 {
697         struct proc *p = lp->lwp_proc;
698         struct vmspace_entry *ve;
699         struct vkernel_lwp *vklp;
700         int error;
701
702         /*
703          * Which vmspace entry was running?
704          */
705         vklp = lp->lwp_vkernel;
706         KKASSERT(vklp);
707         ve = vklp->ve;
708         KKASSERT(ve != NULL);
709
710         /*
711          * Switch the LWP vmspace back to the virtual kernel's VM space.
712          */
713         vklp->ve = NULL;
714         pmap_setlwpvm(lp, p->p_vmspace);
715         KKASSERT(ve->refs > 0);
716         atomic_subtract_int(&ve->refs, 1);
717         /* ve is invalid once we kill our ref */
718
719         /*
720          * Copy the emulated process frame to the virtual kernel process.
721          * The emulated process cannot change TLS descriptors so don't
722          * bother saving them, we already have a copy.
723          *
724          * Restore the virtual kernel's saved context so the virtual kernel
725          * process can resume.
726          */
727         error = copyout(frame, vklp->user_trapframe, sizeof(*frame));
728         bcopy(&vklp->save_trapframe, frame, sizeof(*frame));
729         bcopy(&vklp->save_vextframe.vx_tls, &curthread->td_tls,
730               sizeof(vklp->save_vextframe.vx_tls));
731         set_user_TLS();
732         cpu_vkernel_trap(frame, error);
733 }