1 /* $NetBSD: linux32_machdep.c,v 1.22 2009/05/29 14:19:13 njoly Exp $ */
4 * Copyright (c) 2006 Emmanuel Dreyfus, all rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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. All advertising materials mentioning features or use of this software
15 * must display the following acknowledgement:
16 * This product includes software developed by Emmanuel Dreyfus
17 * 4. The name of the author may not be used to endorse or promote
18 * products derived from this software without specific prior written
21 * THIS SOFTWARE IS PROVIDED BY THE THE AUTHOR AND CONTRIBUTORS ``AS IS''
22 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS
25 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 * POSSIBILITY OF SUCH DAMAGE.
33 #include <sys/cdefs.h>
34 __KERNEL_RCSID(0, "$NetBSD: linux32_machdep.c,v 1.22 2009/05/29 14:19:13 njoly Exp $");
36 #include <sys/param.h>
37 #include <sys/systm.h>
38 #include <sys/signalvar.h>
39 #include <sys/kernel.h>
42 #include <sys/reboot.h>
46 #include <sys/callout.h>
47 #include <sys/malloc.h>
49 #include <sys/msgbuf.h>
50 #include <sys/mount.h>
51 #include <sys/vnode.h>
52 #include <sys/device.h>
53 #include <sys/syscallargs.h>
54 #include <sys/filedesc.h>
55 #include <sys/exec_elf.h>
56 #include <sys/disklabel.h>
57 #include <sys/ioctl.h>
58 #include <miscfs/specfs/specdev.h>
60 #include <machine/netbsd32_machdep.h>
62 #include <compat/netbsd32/netbsd32.h>
63 #include <compat/netbsd32/netbsd32_syscallargs.h>
65 #include <compat/linux/common/linux_signal.h>
66 #include <compat/linux/common/linux_errno.h>
68 #include <compat/linux32/common/linux32_types.h>
69 #include <compat/linux32/common/linux32_errno.h>
70 #include <compat/linux32/common/linux32_machdep.h>
71 #include <compat/linux32/common/linux32_signal.h>
72 #include <compat/linux32/common/linux32_exec.h>
73 #include <compat/linux32/linux32_syscallargs.h>
76 #include <machine/cpufunc.h>
77 #include <machine/psl.h>
78 #include <machine/reg.h>
79 #include <machine/segments.h>
80 #include <machine/specialreg.h>
81 #include <machine/sysarch.h>
82 #include <machine/vmparam.h>
84 extern char linux32_sigcode
[1];
85 extern char linux32_rt_sigcode
[1];
86 extern char linux32_esigcode
[1];
88 extern void (osyscall_return
)(void);
90 static void linux32_save_ucontext(struct lwp
*, struct trapframe
*,
91 const sigset_t
*, struct sigaltstack
*, struct linux32_ucontext
*);
92 static void linux32_save_sigcontext(struct lwp
*, struct trapframe
*,
93 const sigset_t
*, struct linux32_sigcontext
*);
94 static void linux32_rt_sendsig(const ksiginfo_t
*, const sigset_t
*);
95 static void linux32_old_sendsig(const ksiginfo_t
*, const sigset_t
*);
96 static int linux32_restore_sigcontext(struct lwp
*,
97 struct linux32_sigcontext
*, register_t
*);
100 linux32_sendsig(const ksiginfo_t
*ksi
, const sigset_t
*mask
)
102 if (SIGACTION(curproc
, ksi
->ksi_signo
).sa_flags
& SA_SIGINFO
)
103 linux32_rt_sendsig(ksi
, mask
);
105 linux32_old_sendsig(ksi
, mask
);
110 linux32_old_sendsig(const ksiginfo_t
*ksi
, const sigset_t
*mask
)
112 struct lwp
*l
= curlwp
;
113 struct proc
*p
= l
->l_proc
;
114 struct trapframe
*tf
;
115 struct linux32_sigframe
*fp
, frame
;
117 int sig
= ksi
->ksi_signo
;
118 sig_t catcher
= SIGACTION(p
, sig
).sa_handler
;
119 struct sigaltstack
*sas
= &l
->l_sigstk
;
121 tf
= l
->l_md
.md_regs
;
122 /* Do we need to jump onto the signal stack? */
123 onstack
= (sas
->ss_flags
& (SS_DISABLE
| SS_ONSTACK
)) == 0 &&
124 (SIGACTION(p
, sig
).sa_flags
& SA_ONSTACK
) != 0;
127 /* Allocate space for the signal handler context. */
129 fp
= (struct linux32_sigframe
*)((char *)sas
->ss_sp
+
132 fp
= (struct linux32_sigframe
*)tf
->tf_rsp
;
135 /* Build stack frame for signal trampoline. */
136 NETBSD32PTR32(frame
.sf_handler
, catcher
);
137 frame
.sf_sig
= native_to_linux32_signo
[sig
];
139 linux32_save_sigcontext(l
, tf
, mask
, &frame
.sf_sc
);
141 sendsig_reset(l
, sig
);
142 mutex_exit(p
->p_lock
);
143 error
= copyout(&frame
, fp
, sizeof(frame
));
144 mutex_enter(p
->p_lock
);
148 * Process has trashed its stack; give it an illegal
149 * instruction to halt it in its tracks.
156 * Build context to run handler in.
158 tf
->tf_gs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
159 tf
->tf_fs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
160 tf
->tf_es
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
161 tf
->tf_ds
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
162 tf
->tf_rip
= ((long)p
->p_sigctx
.ps_sigcode
) & 0xffffffff;
163 tf
->tf_cs
= GSEL(GUCODE32_SEL
, SEL_UPL
) & 0xffffffff;
164 tf
->tf_rflags
&= ~PSL_CLEARSIG
& 0xffffffff;
165 tf
->tf_rsp
= (long)fp
& 0xffffffff;
166 tf
->tf_ss
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
168 /* Remember that we're now on the signal stack. */
170 sas
->ss_flags
|= SS_ONSTACK
;
176 linux32_rt_sendsig(const ksiginfo_t
*ksi
, const sigset_t
*mask
)
178 struct lwp
*l
= curlwp
;
179 struct proc
*p
= l
->l_proc
;
180 struct trapframe
*tf
;
181 struct linux32_rt_sigframe
*fp
, frame
;
183 linux32_siginfo_t
*lsi
;
184 int sig
= ksi
->ksi_signo
;
185 sig_t catcher
= SIGACTION(p
, sig
).sa_handler
;
186 struct sigaltstack
*sas
= &l
->l_sigstk
;
188 tf
= l
->l_md
.md_regs
;
189 /* Do we need to jump onto the signal stack? */
190 onstack
= (sas
->ss_flags
& (SS_DISABLE
| SS_ONSTACK
)) == 0 &&
191 (SIGACTION(p
, sig
).sa_flags
& SA_ONSTACK
) != 0;
194 /* Allocate space for the signal handler context. */
196 fp
= (struct linux32_rt_sigframe
*)((char *)sas
->ss_sp
+
199 fp
= (struct linux32_rt_sigframe
*)tf
->tf_rsp
;
202 /* Build stack frame for signal trampoline. */
203 NETBSD32PTR32(frame
.sf_handler
, catcher
);
204 frame
.sf_sig
= native_to_linux32_signo
[sig
];
205 NETBSD32PTR32(frame
.sf_sip
, &fp
->sf_si
);
206 NETBSD32PTR32(frame
.sf_ucp
, &fp
->sf_uc
);
209 (void)memset(lsi
, 0, sizeof(frame
.sf_si
));
210 lsi
->lsi_errno
= native_to_linux32_errno
[ksi
->ksi_errno
];
211 lsi
->lsi_code
= native_to_linux_si_code(ksi
->ksi_code
);
212 lsi
->lsi_signo
= frame
.sf_sig
;
213 switch (lsi
->lsi_signo
) {
216 case LINUX32_SIGSEGV
:
218 case LINUX32_SIGTRAP
:
219 NETBSD32PTR32(lsi
->lsi_addr
, ksi
->ksi_addr
);
221 case LINUX32_SIGCHLD
:
222 lsi
->lsi_uid
= ksi
->ksi_uid
;
223 lsi
->lsi_pid
= ksi
->ksi_pid
;
224 lsi
->lsi_utime
= ksi
->ksi_utime
;
225 lsi
->lsi_stime
= ksi
->ksi_stime
;
226 lsi
->lsi_status
= native_to_linux_si_status(ksi
->ksi_code
,
230 lsi
->lsi_band
= ksi
->ksi_band
;
231 lsi
->lsi_fd
= ksi
->ksi_fd
;
234 lsi
->lsi_uid
= ksi
->ksi_uid
;
235 lsi
->lsi_pid
= ksi
->ksi_pid
;
236 if (lsi
->lsi_signo
== LINUX32_SIGALRM
||
237 lsi
->lsi_signo
>= LINUX32_SIGRTMIN
)
238 NETBSD32PTR32(lsi
->lsi_value
.sival_ptr
,
239 ksi
->ksi_value
.sival_ptr
);
243 /* Save register context. */
244 linux32_save_ucontext(l
, tf
, mask
, sas
, &frame
.sf_uc
);
245 sendsig_reset(l
, sig
);
246 mutex_exit(p
->p_lock
);
247 error
= copyout(&frame
, fp
, sizeof(frame
));
248 mutex_enter(p
->p_lock
);
252 * Process has trashed its stack; give it an illegal
253 * instruction to halt it in its tracks.
260 * Build context to run handler in.
262 tf
->tf_gs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
263 tf
->tf_fs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
264 tf
->tf_es
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
265 tf
->tf_ds
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
266 tf
->tf_rip
= (((long)p
->p_sigctx
.ps_sigcode
) +
267 (linux32_rt_sigcode
- linux32_sigcode
)) & 0xffffffff;
268 tf
->tf_cs
= GSEL(GUCODE32_SEL
, SEL_UPL
) & 0xffffffff;
269 tf
->tf_rflags
&= ~PSL_CLEARSIG
& 0xffffffff;
270 tf
->tf_rsp
= (long)fp
& 0xffffffff;
271 tf
->tf_ss
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
273 /* Remember that we're now on the signal stack. */
275 sas
->ss_flags
|= SS_ONSTACK
;
281 linux32_setregs(struct lwp
*l
, struct exec_package
*pack
, u_long stack
)
283 struct pcb
*pcb
= lwp_getpcb(l
);
284 struct trapframe
*tf
;
285 struct proc
*p
= l
->l_proc
;
288 /* If we were using the FPU, forget about it. */
289 if (pcb
->pcb_fpcpu
!= NULL
)
292 #if defined(USER_LDT) && 0
296 netbsd32_adjust_limits(p
);
298 l
->l_md
.md_flags
&= ~MDP_USEDFPU
;
300 pcb
->pcb_savefpu
.fp_fxsave
.fx_fcw
= __Linux_NPXCW__
;
301 pcb
->pcb_savefpu
.fp_fxsave
.fx_mxcsr
= __INITIAL_MXCSR__
;
302 pcb
->pcb_savefpu
.fp_fxsave
.fx_mxcsr_mask
= __INITIAL_MXCSR_MASK__
;
309 tf
= l
->l_md
.md_regs
;
311 tf
->tf_rbx
= (u_int64_t
)p
->p_psstr
& 0xffffffff;
312 tf
->tf_rcx
= pack
->ep_entry
& 0xffffffff;
317 tf
->tf_rsp
= stack
& 0xffffffff;
326 tf
->tf_rip
= pack
->ep_entry
& 0xffffffff;
327 tf
->tf_rflags
= PSL_USERSET
;
328 tf
->tf_cs
= GSEL(GUCODE32_SEL
, SEL_UPL
) & 0xffffffff;
329 tf
->tf_ss
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
330 tf
->tf_ds
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
331 tf
->tf_es
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
332 tf
->tf_fs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
333 tf
->tf_gs
= GSEL(GUDATA32_SEL
, SEL_UPL
) & 0xffffffff;
335 /* XXX frob return address to return via old iret method, not sysret */
336 retaddr
= (void **)tf
- 1;
337 *retaddr
= (void *)osyscall_return
;
342 linux32_save_ucontext(struct lwp
*l
, struct trapframe
*tf
,
343 const sigset_t
*mask
, struct sigaltstack
*sas
, struct linux32_ucontext
*uc
)
347 NETBSD32PTR32(uc
->uc_link
, NULL
);
348 native_to_linux32_sigaltstack(&uc
->uc_stack
, sas
);
349 linux32_save_sigcontext(l
, tf
, mask
, &uc
->uc_mcontext
);
350 native_to_linux32_sigset(&uc
->uc_sigmask
, mask
);
351 (void)memset(&uc
->uc_fpregs_mem
, 0, sizeof(uc
->uc_fpregs_mem
));
355 linux32_save_sigcontext(struct lwp
*l
, struct trapframe
*tf
,
356 const sigset_t
*mask
, struct linux32_sigcontext
*sc
)
358 struct pcb
*pcb
= lwp_getpcb(l
);
360 /* Save register context. */
361 sc
->sc_gs
= tf
->tf_gs
;
362 sc
->sc_fs
= tf
->tf_fs
;
363 sc
->sc_es
= tf
->tf_es
;
364 sc
->sc_ds
= tf
->tf_ds
;
365 sc
->sc_eflags
= tf
->tf_rflags
;
366 sc
->sc_edi
= tf
->tf_rdi
;
367 sc
->sc_esi
= tf
->tf_rsi
;
368 sc
->sc_esp
= tf
->tf_rsp
;
369 sc
->sc_ebp
= tf
->tf_rbp
;
370 sc
->sc_ebx
= tf
->tf_rbx
;
371 sc
->sc_edx
= tf
->tf_rdx
;
372 sc
->sc_ecx
= tf
->tf_rcx
;
373 sc
->sc_eax
= tf
->tf_rax
;
374 sc
->sc_eip
= tf
->tf_rip
;
375 sc
->sc_cs
= tf
->tf_cs
;
376 sc
->sc_esp_at_signal
= tf
->tf_rsp
;
377 sc
->sc_ss
= tf
->tf_ss
;
378 sc
->sc_err
= tf
->tf_err
;
379 sc
->sc_trapno
= tf
->tf_trapno
;
380 sc
->sc_cr2
= pcb
->pcb_cr2
;
381 NETBSD32PTR32(sc
->sc_387
, NULL
);
383 /* Save signal stack. */
384 /* Linux doesn't save the onstack flag in sigframe */
386 /* Save signal mask. */
387 native_to_linux32_old_sigset(&sc
->sc_mask
, mask
);
391 linux32_sys_sigreturn(struct lwp
*l
,
392 const struct linux32_sys_sigreturn_args
*uap
, register_t
*retval
)
395 syscallarg(linux32_sigcontextp_t) scp;
397 struct linux32_sigcontext ctx
;
400 if ((error
= copyin(SCARG_P32(uap
, scp
), &ctx
, sizeof(ctx
))) != 0)
403 return linux32_restore_sigcontext(l
, &ctx
, retval
);
407 linux32_sys_rt_sigreturn(struct lwp
*l
,
408 const struct linux32_sys_rt_sigreturn_args
*uap
, register_t
*retval
)
411 syscallarg(linux32_ucontextp_t) ucp;
413 struct linux32_ucontext ctx
;
416 if ((error
= copyin(SCARG_P32(uap
, ucp
), &ctx
, sizeof(ctx
))) != 0)
419 return linux32_restore_sigcontext(l
, &ctx
.uc_mcontext
, retval
);
423 linux32_restore_sigcontext(struct lwp
*l
, struct linux32_sigcontext
*scp
,
426 struct trapframe
*tf
;
427 struct proc
*p
= l
->l_proc
;
428 struct sigaltstack
*sas
= &l
->l_sigstk
;
432 /* Restore register context. */
433 tf
= l
->l_md
.md_regs
;
436 * Check for security violations. If we're returning to
437 * protected mode, the CPU will validate the segment registers
438 * automatically and generate a trap on violations. We handle
439 * the trap, rather than doing all of the checking here.
441 if (((scp
->sc_eflags
^ tf
->tf_rflags
) & PSL_USERSTATIC
) != 0 ||
442 !USERMODE(scp
->sc_cs
, scp
->sc_eflags
))
445 if (scp
->sc_fs
!= 0 && !VALID_USER_DSEL32(scp
->sc_fs
))
448 if (scp
->sc_gs
!= 0 && !VALID_USER_DSEL32(scp
->sc_gs
))
451 if (scp
->sc_es
!= 0 && !VALID_USER_DSEL32(scp
->sc_es
))
454 if (!VALID_USER_DSEL32(scp
->sc_ds
) ||
455 !VALID_USER_DSEL32(scp
->sc_ss
))
458 if (scp
->sc_eip
>= VM_MAXUSER_ADDRESS32
)
461 tf
->tf_gs
= (register_t
)scp
->sc_gs
& 0xffffffff;
462 tf
->tf_fs
= (register_t
)scp
->sc_fs
& 0xffffffff;
463 tf
->tf_es
= (register_t
)scp
->sc_es
& 0xffffffff;
464 tf
->tf_ds
= (register_t
)scp
->sc_ds
& 0xffffffff;
465 tf
->tf_rflags
&= ~PSL_USER
;
466 tf
->tf_rflags
|= ((register_t
)scp
->sc_eflags
& PSL_USER
);
467 tf
->tf_rdi
= (register_t
)scp
->sc_edi
& 0xffffffff;
468 tf
->tf_rsi
= (register_t
)scp
->sc_esi
& 0xffffffff;
469 tf
->tf_rbp
= (register_t
)scp
->sc_ebp
& 0xffffffff;
470 tf
->tf_rbx
= (register_t
)scp
->sc_ebx
& 0xffffffff;
471 tf
->tf_rdx
= (register_t
)scp
->sc_edx
& 0xffffffff;
472 tf
->tf_rcx
= (register_t
)scp
->sc_ecx
& 0xffffffff;
473 tf
->tf_rax
= (register_t
)scp
->sc_eax
& 0xffffffff;
474 tf
->tf_rip
= (register_t
)scp
->sc_eip
& 0xffffffff;
475 tf
->tf_cs
= (register_t
)scp
->sc_cs
& 0xffffffff;
476 tf
->tf_rsp
= (register_t
)scp
->sc_esp_at_signal
& 0xffffffff;
477 tf
->tf_ss
= (register_t
)scp
->sc_ss
& 0xffffffff;
479 mutex_enter(p
->p_lock
);
481 /* Restore signal stack. */
483 ((char *)NETBSD32IPTR64(scp
->sc_esp_at_signal
)
484 - (char *)sas
->ss_sp
);
485 if (ss_gap
>= 0 && ss_gap
< sas
->ss_size
)
486 sas
->ss_flags
|= SS_ONSTACK
;
488 sas
->ss_flags
&= ~SS_ONSTACK
;
490 /* Restore signal mask. */
491 linux32_old_to_native_sigset(&mask
, &scp
->sc_mask
);
492 (void) sigprocmask1(l
, SIG_SETMASK
, &mask
, 0);
494 mutex_exit(p
->p_lock
);
497 printf("linux32_sigreturn: rip = 0x%lx, rsp = 0x%lx, flags = 0x%lx\n",
498 tf
->tf_rip
, tf
->tf_rsp
, tf
->tf_rflags
);