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