Merge from vendor branch LIBARCHIVE:
[dragonfly.git] / sys / emulation / linux / i386 / linux_machdep.c
1 /*-
2  * Copyright (c) 2000 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer 
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/sys/i386/linux/linux_machdep.c,v 1.6.2.4 2001/11/05 19:08:23 marcel Exp $
29  * $DragonFly: src/sys/emulation/linux/i386/linux_machdep.c,v 1.23 2007/07/30 17:41:23 pavalos Exp $
30  */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/imgact.h>
35 #include <sys/kern_syscall.h>
36 #include <sys/lock.h>
37 #include <sys/mman.h>
38 #include <sys/nlookup.h>
39 #include <sys/proc.h>
40 #include <sys/resource.h>
41 #include <sys/resourcevar.h>
42 #include <sys/sysproto.h>
43 #include <sys/unistd.h>
44 #include <sys/wait.h>
45
46 #include <machine/frame.h>
47 #include <machine/psl.h>
48 #include <machine/segments.h>
49 #include <machine/sysarch.h>
50
51 #include <vm/vm.h>
52 #include <vm/pmap.h>
53 #include <vm/vm_map.h>
54
55 #include "linux.h"
56 #include "linux_proto.h"
57 #include "../linux_ipc.h"
58 #include "../linux_signal.h"
59 #include "../linux_util.h"
60
61 struct l_descriptor {
62         l_uint          entry_number;
63         l_ulong         base_addr;
64         l_uint          limit;
65         l_uint          seg_32bit:1;
66         l_uint          contents:2;
67         l_uint          read_exec_only:1;
68         l_uint          limit_in_pages:1;
69         l_uint          seg_not_present:1;
70         l_uint          useable:1;
71 };
72
73 struct l_old_select_argv {
74         l_int           nfds;
75         l_fd_set        *readfds;
76         l_fd_set        *writefds;
77         l_fd_set        *exceptfds;
78         struct l_timeval        *timeout;
79 };
80
81 int
82 linux_to_bsd_sigaltstack(int lsa)
83 {
84         int bsa = 0;
85
86         if (lsa & LINUX_SS_DISABLE)
87                 bsa |= SS_DISABLE;
88         if (lsa & LINUX_SS_ONSTACK)
89                 bsa |= SS_ONSTACK;
90         return (bsa);
91 }
92
93 int
94 bsd_to_linux_sigaltstack(int bsa)
95 {
96         int lsa = 0;
97
98         if (bsa & SS_DISABLE)
99                 lsa |= LINUX_SS_DISABLE;
100         if (bsa & SS_ONSTACK)
101                 lsa |= LINUX_SS_ONSTACK;
102         return (lsa);
103 }
104
105 int
106 sys_linux_execve(struct linux_execve_args *args)
107 {
108         struct nlookupdata nd;
109         struct image_args exec_args;
110         char *path;
111         int error;
112
113         error = linux_copyin_path(args->path, &path, LINUX_PATH_EXISTS);
114         if (error)
115                 return (error);
116 #ifdef DEBUG
117         if (ldebug(execve))
118                 kprintf(ARGS(execve, "%s"), path);
119 #endif
120         error = nlookup_init(&nd, path, UIO_SYSSPACE, NLC_FOLLOW);
121         if (error == 0) {
122                 error = exec_copyin_args(&exec_args, path, PATH_SYSSPACE,
123                                         args->argp, args->envp);
124         }
125         if (error == 0)
126                 error = kern_execve(&nd, &exec_args);
127         nlookup_done(&nd);
128
129         /*
130          * The syscall result is returned in registers to the new program.
131          * Linux will register %edx as an atexit function and we must be
132          * sure to set it to 0.  XXX
133          */
134         if (error == 0)
135                 args->sysmsg_result64 = 0;
136
137         exec_free_args(&exec_args);
138         linux_free_path(&path);
139
140         if (error < 0) {
141                 /* We hit a lethal error condition.  Let's die now. */
142                 exit1(W_EXITCODE(0, SIGABRT));
143                 /* NOTREACHED */
144         }
145
146         return(error);
147 }
148
149 struct l_ipc_kludge {
150         struct l_msgbuf *msgp;
151         l_long msgtyp;
152 };
153
154 int
155 sys_linux_ipc(struct linux_ipc_args *args)
156 {
157         int error = 0;
158
159         switch (args->what & 0xFFFF) {
160         case LINUX_SEMOP: {
161                 struct linux_semop_args a;
162
163                 a.semid = args->arg1;
164                 a.tsops = args->ptr;
165                 a.nsops = args->arg2;
166                 a.sysmsg_lresult = 0;
167                 error = linux_semop(&a);
168                 args->sysmsg_lresult = a.sysmsg_lresult;
169                 break;
170         }
171         case LINUX_SEMGET: {
172                 struct linux_semget_args a;
173
174                 a.key = args->arg1;
175                 a.nsems = args->arg2;
176                 a.semflg = args->arg3;
177                 a.sysmsg_lresult = 0;
178                 error = linux_semget(&a);
179                 args->sysmsg_lresult = a.sysmsg_lresult;
180                 break;
181         }
182         case LINUX_SEMCTL: {
183                 struct linux_semctl_args a;
184                 int error;
185
186                 a.semid = args->arg1;
187                 a.semnum = args->arg2;
188                 a.cmd = args->arg3;
189                 a.sysmsg_lresult = 0;
190                 error = copyin((caddr_t)args->ptr, &a.arg, sizeof(a.arg));
191                 if (error)
192                         return (error);
193                 error = linux_semctl(&a);
194                 args->sysmsg_lresult = a.sysmsg_lresult;
195                 break;
196         }
197         case LINUX_MSGSND: {
198                 struct linux_msgsnd_args a;
199
200                 a.msqid = args->arg1;
201                 a.msgp = args->ptr;
202                 a.msgsz = args->arg2;
203                 a.msgflg = args->arg3;
204                 a.sysmsg_lresult = 0;
205                 error = linux_msgsnd(&a);
206                 args->sysmsg_lresult = a.sysmsg_lresult;
207                 break;
208         }
209         case LINUX_MSGRCV: {
210                 struct linux_msgrcv_args a;
211
212                 a.msqid = args->arg1;
213                 a.msgsz = args->arg2;
214                 a.msgflg = args->arg3;
215                 a.sysmsg_lresult = 0;
216                 if ((args->what >> 16) == 0) {
217                         struct l_ipc_kludge tmp;
218                         int error;
219
220                         if (args->ptr == NULL)
221                                 return (EINVAL);
222                         error = copyin((caddr_t)args->ptr, &tmp, sizeof(tmp));
223                         if (error)
224                                 return (error);
225                         a.msgp = tmp.msgp;
226                         a.msgtyp = tmp.msgtyp;
227                 } else {
228                         a.msgp = args->ptr;
229                         a.msgtyp = args->arg5;
230                 }
231                 error = linux_msgrcv(&a);
232                 args->sysmsg_lresult = a.sysmsg_lresult;
233                 break;
234         }
235         case LINUX_MSGGET: {
236                 struct linux_msgget_args a;
237
238                 a.key = args->arg1;
239                 a.msgflg = args->arg2;
240                 a.sysmsg_lresult = 0;
241                 error = linux_msgget(&a);
242                 args->sysmsg_lresult = a.sysmsg_lresult;
243                 break;
244         }
245         case LINUX_MSGCTL: {
246                 struct linux_msgctl_args a;
247
248                 a.msqid = args->arg1;
249                 a.cmd = args->arg2;
250                 a.buf = args->ptr;
251                 a.sysmsg_lresult = 0;
252                 error = linux_msgctl(&a);
253                 args->sysmsg_lresult = a.sysmsg_lresult;
254                 break;
255         }
256         case LINUX_SHMAT: {
257                 struct linux_shmat_args a;
258
259                 a.shmid = args->arg1;
260                 a.shmaddr = args->ptr;
261                 a.shmflg = args->arg2;
262                 a.raddr = (l_ulong *)args->arg3;
263                 a.sysmsg_lresult = 0;
264                 error = linux_shmat(&a);
265                 args->sysmsg_lresult = a.sysmsg_lresult;
266                 break;
267         }
268         case LINUX_SHMDT: {
269                 struct linux_shmdt_args a;
270
271                 a.shmaddr = args->ptr;
272                 a.sysmsg_lresult = 0;
273                 error = linux_shmdt(&a);
274                 args->sysmsg_lresult = a.sysmsg_lresult;
275                 break;
276         }
277         case LINUX_SHMGET: {
278                 struct linux_shmget_args a;
279
280                 a.key = args->arg1;
281                 a.size = args->arg2;
282                 a.shmflg = args->arg3;
283                 a.sysmsg_lresult = 0;
284                 error = linux_shmget(&a);
285                 args->sysmsg_lresult = a.sysmsg_lresult;
286                 break;
287         }
288         case LINUX_SHMCTL: {
289                 struct linux_shmctl_args a;
290
291                 a.shmid = args->arg1;
292                 a.cmd = args->arg2;
293                 a.buf = args->ptr;
294                 a.sysmsg_lresult = 0;
295                 error = linux_shmctl(&a);
296                 args->sysmsg_lresult = a.sysmsg_lresult;
297                 break;
298         }
299         default:
300                 error = EINVAL;
301                 break;
302         }
303         return(error);
304 }
305
306 int
307 sys_linux_old_select(struct linux_old_select_args *args)
308 {
309         struct l_old_select_argv linux_args;
310         struct linux_select_args newsel;
311         int error;
312
313 #ifdef DEBUG
314         if (ldebug(old_select))
315                 kprintf(ARGS(old_select, "%p"), args->ptr);
316 #endif
317
318         error = copyin((caddr_t)args->ptr, &linux_args, sizeof(linux_args));
319         if (error)
320                 return (error);
321
322         newsel.sysmsg_result = 0;
323         newsel.nfds = linux_args.nfds;
324         newsel.readfds = linux_args.readfds;
325         newsel.writefds = linux_args.writefds;
326         newsel.exceptfds = linux_args.exceptfds;
327         newsel.timeout = linux_args.timeout;
328         error = sys_linux_select(&newsel);
329         args->sysmsg_result = newsel.sysmsg_result;
330         return(error);
331 }
332
333 int
334 sys_linux_fork(struct linux_fork_args *args)
335 {
336         int error;
337
338 #ifdef DEBUG
339         if (ldebug(fork))
340                 kprintf(ARGS(fork, ""));
341 #endif
342
343         if ((error = sys_fork((struct fork_args *)args)) != 0)
344                 return (error);
345
346         if (args->sysmsg_result == 1)
347                 args->sysmsg_result = 0;
348         return (0);
349 }
350
351 int
352 sys_linux_exit_group(struct linux_exit_group_args *args)
353 {
354         struct exit_args newargs;
355         int error;
356
357         newargs.sysmsg_result = 0;
358         newargs.rval = args->rval;
359         error = sys_exit(&newargs);
360         args->sysmsg_result = newargs.sysmsg_result;
361         return (error);
362 }
363
364 int
365 sys_linux_vfork(struct linux_vfork_args *args)
366 {
367         int error;
368
369 #ifdef DEBUG
370         if (ldebug(vfork))
371                 kprintf(ARGS(vfork, ""));
372 #endif
373
374         if ((error = sys_vfork((struct vfork_args *)args)) != 0)
375                 return (error);
376         /* Are we the child? */
377         if (args->sysmsg_result == 1)
378                 args->sysmsg_result = 0;
379         return (0);
380 }
381
382 #define CLONE_VM        0x100
383 #define CLONE_FS        0x200
384 #define CLONE_FILES     0x400
385 #define CLONE_SIGHAND   0x800
386 #define CLONE_PID       0x1000
387
388 int
389 sys_linux_clone(struct linux_clone_args *args)
390 {
391         int error, ff = RFPROC;
392         struct proc *p2;
393         int exit_signal;
394         vm_offset_t start;
395         struct rfork_args rf_args;
396
397 #ifdef DEBUG
398         if (ldebug(clone)) {
399                 kprintf(ARGS(clone, "flags %x, stack %x"), 
400                     (unsigned int)args->flags, (unsigned int)args->stack);
401                 if (args->flags & CLONE_PID)
402                         kprintf(LMSG("CLONE_PID not yet supported"));
403         }
404 #endif
405
406         if (!args->stack)
407                 return (EINVAL);
408
409         exit_signal = args->flags & 0x000000ff;
410         if (exit_signal >= LINUX_NSIG)
411                 return (EINVAL);
412
413         if (exit_signal <= LINUX_SIGTBLSZ)
414                 exit_signal = linux_to_bsd_signal[_SIG_IDX(exit_signal)];
415
416         /* RFTHREAD probably not necessary here, but it shouldn't hurt */
417         ff |= RFTHREAD;
418
419         if (args->flags & CLONE_VM)
420                 ff |= RFMEM;
421         if (args->flags & CLONE_SIGHAND)
422                 ff |= RFSIGSHARE;
423         if (!(args->flags & CLONE_FILES))
424                 ff |= RFFDG;
425
426         error = 0;
427         start = 0;
428
429         rf_args.flags = ff;
430         rf_args.sysmsg_result = 0;
431         if ((error = sys_rfork(&rf_args)) != 0)
432                 return (error);
433         args->sysmsg_result = rf_args.sysmsg_result;
434
435         p2 = pfind(rf_args.sysmsg_result);
436         if (p2 == NULL)
437                 return (ESRCH);
438
439         p2->p_sigparent = exit_signal;
440         ONLY_LWP_IN_PROC(p2)->lwp_md.md_regs->tf_esp =
441             (unsigned int)args->stack;
442
443 #ifdef DEBUG
444         if (ldebug(clone))
445                 kprintf(LMSG("clone: successful rfork to %ld"),
446                     (long)p2->p_pid);
447 #endif
448
449         return (0);
450 }
451
452 /* XXX move */
453 struct l_mmap_argv {
454         l_caddr_t       addr;
455         l_int           len;
456         l_int           prot;
457         l_int           flags;
458         l_int           fd;
459         l_int           pos;
460 };
461
462 #define STACK_SIZE  (2 * 1024 * 1024)
463 #define GUARD_SIZE  (4 * PAGE_SIZE)
464
465 static int
466 linux_mmap_common(caddr_t linux_addr, size_t linux_len, int linux_prot,
467     int linux_flags, int linux_fd, off_t pos, void **res)
468 {
469         struct thread *td = curthread;
470         struct proc *p = td->td_proc;
471         caddr_t addr;
472         void *new;
473         int error, flags, len, prot, fd;
474
475         flags = 0;
476         if (linux_flags & LINUX_MAP_SHARED)
477                 flags |= MAP_SHARED;
478         if (linux_flags & LINUX_MAP_PRIVATE)
479                 flags |= MAP_PRIVATE;
480         if (linux_flags & LINUX_MAP_FIXED)
481                 flags |= MAP_FIXED;
482         if (linux_flags & LINUX_MAP_ANON) {
483                 flags |= MAP_ANON;
484         } else {
485                 flags |= MAP_NOSYNC;
486         }
487         if (linux_flags & LINUX_MAP_GROWSDOWN) {
488                 flags |= MAP_STACK;
489                 /* The linux MAP_GROWSDOWN option does not limit auto
490                  * growth of the region.  Linux mmap with this option
491                  * takes as addr the inital BOS, and as len, the initial
492                  * region size.  It can then grow down from addr without
493                  * limit.  However, linux threads has an implicit internal
494                  * limit to stack size of STACK_SIZE.  Its just not
495                  * enforced explicitly in linux.  But, here we impose
496                  * a limit of (STACK_SIZE - GUARD_SIZE) on the stack
497                  * region, since we can do this with our mmap.
498                  *
499                  * Our mmap with MAP_STACK takes addr as the maximum
500                  * downsize limit on BOS, and as len the max size of
501                  * the region.  It them maps the top SGROWSIZ bytes,
502                  * and autgrows the region down, up to the limit
503                  * in addr.
504                  *
505                  * If we don't use the MAP_STACK option, the effect
506                  * of this code is to allocate a stack region of a
507                  * fixed size of (STACK_SIZE - GUARD_SIZE).
508                  */
509
510                 /* This gives us TOS */
511                 addr = linux_addr + linux_len;
512
513                 if (addr > p->p_vmspace->vm_maxsaddr) {
514                         /* Some linux apps will attempt to mmap
515                          * thread stacks near the top of their
516                          * address space.  If their TOS is greater
517                          * than vm_maxsaddr, vm_map_growstack()
518                          * will confuse the thread stack with the
519                          * process stack and deliver a SEGV if they
520                          * attempt to grow the thread stack past their
521                          * current stacksize rlimit.  To avoid this,
522                          * adjust vm_maxsaddr upwards to reflect
523                          * the current stacksize rlimit rather
524                          * than the maximum possible stacksize.
525                          * It would be better to adjust the
526                          * mmap'ed region, but some apps do not check
527                          * mmap's return value.
528                          */
529                         p->p_vmspace->vm_maxsaddr = (char *)USRSTACK -
530                             p->p_rlimit[RLIMIT_STACK].rlim_cur;
531                 }
532
533                 /* This gives us our maximum stack size */
534                 if (linux_len > STACK_SIZE - GUARD_SIZE) {
535                         len = linux_len;
536                 } else {
537                         len = STACK_SIZE - GUARD_SIZE;
538                 }
539                 /* This gives us a new BOS.  If we're using VM_STACK, then
540                  * mmap will just map the top SGROWSIZ bytes, and let
541                  * the stack grow down to the limit at BOS.  If we're
542                  * not using VM_STACK we map the full stack, since we
543                  * don't have a way to autogrow it.
544                  */
545                 addr -= len;
546         } else {
547                 addr = linux_addr;
548                 len = linux_len;
549         }
550
551         prot = linux_prot | PROT_READ;
552         if (linux_flags & LINUX_MAP_ANON) {
553                 fd = -1;
554         } else {
555                 fd = linux_fd;
556         }
557         
558 #ifdef DEBUG
559         if (ldebug(mmap) || ldebug(mmap2))
560                 kprintf("-> (%p, %d, %d, 0x%08x, %d, %lld)\n",
561                     addr, len, prot, flags, fd, pos);
562 #endif
563         error = kern_mmap(curproc->p_vmspace, addr, len,
564                           prot, flags, fd, pos, &new);
565
566         if (error == 0)
567                 *res = new;
568         return (error);
569 }
570
571 int
572 sys_linux_mmap(struct linux_mmap_args *args)
573 {
574         struct l_mmap_argv linux_args;
575         int error;
576
577         error = copyin((caddr_t)args->ptr, &linux_args, sizeof(linux_args));
578         if (error)
579                 return (error);
580
581 #ifdef DEBUG
582         if (ldebug(mmap))
583                 kprintf(ARGS(mmap, "%p, %d, %d, 0x%08x, %d, %d"),
584                     (void *)linux_args.addr, linux_args.len, linux_args.prot,
585                     linux_args.flags, linux_args.fd, linux_args.pos);
586 #endif
587         error = linux_mmap_common(linux_args.addr, linux_args.len,
588             linux_args.prot, linux_args.flags, linux_args.fd,
589             linux_args.pos, &args->sysmsg_resultp);
590 #ifdef DEBUG
591         if (ldebug(mmap))
592                 kprintf("-> %p\n", args->sysmsg_resultp);
593 #endif
594         return(error);
595 }
596
597 int
598 sys_linux_mmap2(struct linux_mmap2_args *args)
599 {
600         int error;
601
602 #ifdef DEBUG
603         if (ldebug(mmap2))
604                 kprintf(ARGS(mmap2, "%p, %d, %d, 0x%08x, %d, %d"),
605                     (void *)args->addr, args->len, args->prot, args->flags,
606                     args->fd, args->pgoff);
607 #endif
608         error = linux_mmap_common((void *)args->addr, args->len, args->prot,
609             args->flags, args->fd, args->pgoff * PAGE_SIZE,
610             &args->sysmsg_resultp);
611 #ifdef DEBUG
612         if (ldebug(mmap2))
613                 kprintf("-> %p\n", args->sysmsg_resultp);
614 #endif
615         return (error);
616 }
617
618 int
619 sys_linux_pipe(struct linux_pipe_args *args)
620 {
621         int error;
622         int reg_edx;
623         struct pipe_args bsd_args;
624
625 #ifdef DEBUG
626         if (ldebug(pipe))
627                 kprintf(ARGS(pipe, "*"));
628 #endif
629
630         reg_edx = args->sysmsg_fds[1];
631         error = sys_pipe(&bsd_args);
632         if (error) {
633                 args->sysmsg_fds[1] = reg_edx;
634                 return (error);
635         }
636
637         error = copyout(bsd_args.sysmsg_fds, args->pipefds, 2*sizeof(int));
638         if (error) {
639                 args->sysmsg_fds[1] = reg_edx;
640                 return (error);
641         }
642
643         args->sysmsg_fds[1] = reg_edx;
644         args->sysmsg_fds[0] = 0;
645         return (0);
646 }
647
648 int
649 sys_linux_ioperm(struct linux_ioperm_args *args)
650 {
651         struct sysarch_args sa;
652         struct i386_ioperm_args *iia;
653         caddr_t sg;
654         int error;
655
656         sg = stackgap_init();
657         iia = stackgap_alloc(&sg, sizeof(struct i386_ioperm_args));
658         iia->start = args->start;
659         iia->length = args->length;
660         iia->enable = args->enable;
661         sa.sysmsg_resultp = NULL;
662         sa.op = I386_SET_IOPERM;
663         sa.parms = (char *)iia;
664         error = sys_sysarch(&sa);
665         args->sysmsg_resultp = sa.sysmsg_resultp;
666         return(error);
667 }
668
669 int
670 sys_linux_iopl(struct linux_iopl_args *args)
671 {
672         struct thread *td = curthread;
673         struct lwp *lp = td->td_lwp;
674         int error;
675
676         KKASSERT(lp);
677
678         if (args->level < 0 || args->level > 3)
679                 return (EINVAL);
680         if ((error = suser(td)) != 0)
681                 return (error);
682         if (securelevel > 0)
683                 return (EPERM);
684         lp->lwp_md.md_regs->tf_eflags =
685             (lp->lwp_md.md_regs->tf_eflags & ~PSL_IOPL) |
686             (args->level * (PSL_IOPL / 3));
687         return (0);
688 }
689
690 int
691 sys_linux_modify_ldt(struct linux_modify_ldt_args *uap)
692 {
693         int error;
694         caddr_t sg;
695         struct sysarch_args args;
696         struct i386_ldt_args *ldt;
697         struct l_descriptor ld;
698         union descriptor *desc;
699
700         sg = stackgap_init();
701
702         if (uap->ptr == NULL)
703                 return (EINVAL);
704
705         switch (uap->func) {
706         case 0x00: /* read_ldt */
707                 ldt = stackgap_alloc(&sg, sizeof(*ldt));
708                 ldt->start = 0;
709                 ldt->descs = uap->ptr;
710                 ldt->num = uap->bytecount / sizeof(union descriptor);
711                 args.op = I386_GET_LDT;
712                 args.parms = (char*)ldt;
713                 args.sysmsg_result = 0;
714                 error = sys_sysarch(&args);
715                 uap->sysmsg_result = args.sysmsg_result *
716                                             sizeof(union descriptor);
717                 break;
718         case 0x01: /* write_ldt */
719         case 0x11: /* write_ldt */
720                 if (uap->bytecount != sizeof(ld))
721                         return (EINVAL);
722
723                 error = copyin(uap->ptr, &ld, sizeof(ld));
724                 if (error)
725                         return (error);
726
727                 ldt = stackgap_alloc(&sg, sizeof(*ldt));
728                 desc = stackgap_alloc(&sg, sizeof(*desc));
729                 ldt->start = ld.entry_number;
730                 ldt->descs = desc;
731                 ldt->num = 1;
732                 desc->sd.sd_lolimit = (ld.limit & 0x0000ffff);
733                 desc->sd.sd_hilimit = (ld.limit & 0x000f0000) >> 16;
734                 desc->sd.sd_lobase = (ld.base_addr & 0x00ffffff);
735                 desc->sd.sd_hibase = (ld.base_addr & 0xff000000) >> 24;
736                 desc->sd.sd_type = SDT_MEMRO | ((ld.read_exec_only ^ 1) << 1) |
737                         (ld.contents << 2);
738                 desc->sd.sd_dpl = 3;
739                 desc->sd.sd_p = (ld.seg_not_present ^ 1);
740                 desc->sd.sd_xx = 0;
741                 desc->sd.sd_def32 = ld.seg_32bit;
742                 desc->sd.sd_gran = ld.limit_in_pages;
743                 args.op = I386_SET_LDT;
744                 args.parms = (char*)ldt;
745                 args.sysmsg_result = 0;
746                 error = sys_sysarch(&args);
747                 uap->sysmsg_result = args.sysmsg_result;
748                 break;
749         default:
750                 error = EINVAL;
751                 break;
752         }
753
754         return (error);
755 }
756
757 int
758 sys_linux_sigaction(struct linux_sigaction_args *args)
759 {
760         l_osigaction_t osa;
761         l_sigaction_t linux_act, linux_oact;
762         struct sigaction act, oact;
763         int error;
764
765 #ifdef DEBUG
766         if (ldebug(sigaction))
767                 kprintf(ARGS(sigaction, "%d, %p, %p"),
768                     args->sig, (void *)args->nsa, (void *)args->osa);
769 #endif
770
771         if (args->nsa) {
772                 error = copyin(args->nsa, &osa, sizeof(l_osigaction_t));
773                 if (error)
774                         return (error);
775                 linux_act.lsa_handler = osa.lsa_handler;
776                 linux_act.lsa_flags = osa.lsa_flags;
777                 linux_act.lsa_restorer = osa.lsa_restorer;
778                 LINUX_SIGEMPTYSET(linux_act.lsa_mask);
779                 linux_act.lsa_mask.__bits[0] = osa.lsa_mask;
780                 linux_to_bsd_sigaction(&linux_act, &act);
781         }
782
783         error = kern_sigaction(args->sig, args->nsa ? &act : NULL,
784             args->osa ? &oact : NULL);
785
786         if (args->osa != NULL && !error) {
787                 bsd_to_linux_sigaction(&oact, &linux_oact);
788                 osa.lsa_handler = linux_oact.lsa_handler;
789                 osa.lsa_flags = linux_oact.lsa_flags;
790                 osa.lsa_restorer = linux_oact.lsa_restorer;
791                 osa.lsa_mask = linux_oact.lsa_mask.__bits[0];
792                 error = copyout(&osa, args->osa, sizeof(l_osigaction_t));
793         }
794         return (error);
795 }
796
797 /*
798  * Linux has two extra args, restart and oldmask.  We dont use these,
799  * but it seems that "restart" is actually a context pointer that
800  * enables the signal to happen with a different register set.
801  */
802 int
803 sys_linux_sigsuspend(struct linux_sigsuspend_args *args)
804 {
805         l_sigset_t linux_mask;
806         sigset_t mask;
807         int error;
808
809 #ifdef DEBUG
810         if (ldebug(sigsuspend))
811                 kprintf(ARGS(sigsuspend, "%08lx"), (unsigned long)args->mask);
812 #endif
813
814         LINUX_SIGEMPTYSET(mask);
815         mask.__bits[0] = args->mask;
816         linux_to_bsd_sigset(&linux_mask, &mask);
817
818         error = kern_sigsuspend(&mask);
819
820         return(error);
821 }
822
823 int
824 sys_linux_rt_sigsuspend(struct linux_rt_sigsuspend_args *uap)
825 {
826         l_sigset_t linux_mask;
827         sigset_t mask;
828         int error;
829
830 #ifdef DEBUG
831         if (ldebug(rt_sigsuspend))
832                 kprintf(ARGS(rt_sigsuspend, "%p, %d"),
833                     (void *)uap->newset, uap->sigsetsize);
834 #endif
835
836         if (uap->sigsetsize != sizeof(l_sigset_t))
837                 return (EINVAL);
838
839         error = copyin(uap->newset, &linux_mask, sizeof(l_sigset_t));
840         if (error)
841                 return (error);
842
843         linux_to_bsd_sigset(&linux_mask, &mask);
844
845         error = kern_sigsuspend(&mask);
846
847         return(error);
848 }
849
850 int
851 sys_linux_pause(struct linux_pause_args *args)
852 {
853         struct thread *td = curthread;
854         struct lwp *lp = td->td_lwp;
855         sigset_t mask;
856         int error;
857
858 #ifdef DEBUG
859         if (ldebug(pause))
860                 kprintf(ARGS(pause, ""));
861 #endif
862
863         mask = lp->lwp_sigmask;
864
865         error = kern_sigsuspend(&mask);
866
867         return(error);
868 }
869
870 int
871 sys_linux_sigaltstack(struct linux_sigaltstack_args *uap)
872 {
873         stack_t ss, oss;
874         l_stack_t linux_ss;
875         int error;
876
877 #ifdef DEBUG
878         if (ldebug(sigaltstack))
879                 kprintf(ARGS(sigaltstack, "%p, %p"), uap->uss, uap->uoss);
880 #endif
881
882         if (uap->uss) {
883                 error = copyin(uap->uss, &linux_ss, sizeof(l_stack_t));
884                 if (error)
885                         return (error);
886
887                 ss.ss_sp = linux_ss.ss_sp;
888                 ss.ss_size = linux_ss.ss_size;
889                 ss.ss_flags = linux_to_bsd_sigaltstack(linux_ss.ss_flags);
890         }
891
892         error = kern_sigaltstack(uap->uss ? &ss : NULL,
893             uap->uoss ? &oss : NULL);
894
895         if (error == 0 && uap->uoss) {
896                 linux_ss.ss_sp = oss.ss_sp;
897                 linux_ss.ss_size = oss.ss_size;
898                 linux_ss.ss_flags = bsd_to_linux_sigaltstack(oss.ss_flags);
899                 error = copyout(&linux_ss, uap->uoss, sizeof(l_stack_t));
900         }
901
902         return (error);
903 }