1 | /* $NetBSD: linux_trap.c,v 1.11 2012/02/19 21:06:35 rmind Exp $ */ |
2 | |
3 | /*- |
4 | * Copyright (c) 2001 The NetBSD Foundation, Inc. |
5 | * All rights reserved. |
6 | * |
7 | * This code is derived from software contributed to The NetBSD Foundation |
8 | * by Christos Zoulas. |
9 | * |
10 | * Redistribution and use in source and binary forms, with or without |
11 | * modification, are permitted provided that the following conditions |
12 | * are met: |
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 the |
17 | * documentation and/or other materials provided with the distribution. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
20 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
21 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
22 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
23 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
24 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
25 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
26 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
27 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
28 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
29 | * POSSIBILITY OF SUCH DAMAGE. |
30 | */ |
31 | |
32 | /* |
33 | * x86 Trap and System call handling |
34 | */ |
35 | |
36 | #include <sys/cdefs.h> |
37 | __KERNEL_RCSID(0, "$NetBSD: linux_trap.c,v 1.11 2012/02/19 21:06:35 rmind Exp $" ); |
38 | |
39 | #include <sys/param.h> |
40 | #include <sys/systm.h> |
41 | #include <sys/proc.h> |
42 | #include <sys/acct.h> |
43 | #include <sys/kernel.h> |
44 | #include <sys/signal.h> |
45 | #include <sys/signalvar.h> |
46 | #include <sys/syscall.h> |
47 | |
48 | #include <uvm/uvm_extern.h> |
49 | |
50 | #include <machine/cpu.h> |
51 | #include <machine/cpufunc.h> |
52 | #include <machine/psl.h> |
53 | #include <machine/reg.h> |
54 | #include <machine/trap.h> |
55 | #include <machine/userret.h> |
56 | |
57 | #include <compat/linux/common/linux_exec.h> |
58 | |
59 | #ifndef DEBUG_LINUX |
60 | #define DPRINTF(a) |
61 | #else |
62 | #define DPRINTF(a) uprintf a |
63 | #endif |
64 | |
65 | struct linux_user_desc { |
66 | unsigned int entry_number; |
67 | unsigned int base_addr; |
68 | unsigned int limit; |
69 | unsigned int seg_32bit:1; |
70 | unsigned int contents:2; |
71 | unsigned int read_exec_only:1; |
72 | unsigned int limit_in_pages:1; |
73 | unsigned int seg_not_present:1; |
74 | unsigned int useable:1; |
75 | }; |
76 | |
77 | #define LINUX_T_DIVIDE 0 |
78 | #define LINUX_T_DEBUG 1 |
79 | #define LINUX_T_NMI 2 |
80 | #define LINUX_T_INT3 3 |
81 | #define LINUX_T_OVERFLOW 4 |
82 | #define LINUX_T_BOUNDS 5 |
83 | #define LINUX_T_INVALID_OP 6 |
84 | #define LINUX_T_DEVICE_NOT_AVAIL 7 |
85 | #define LINUX_T_DOUBLE_FAULT 8 |
86 | #define LINUX_T_COPROC_SEG_OVERRUN 9 |
87 | #define LINUX_T_INVALID_TSS 10 |
88 | #define LINUX_T_SEG_NOT_PRESENT 11 |
89 | #define LINUX_T_STACK_SEG_FAULT 12 |
90 | #define LINUX_T_GENERAL_PROT_FAULT 13 |
91 | #define LINUX_T_PAGE_FAULT 14 |
92 | #define LINUX_T_SPURIOUS_INTERRUPT 15 |
93 | #define LINUX_T_COPROC_ERROR 16 |
94 | #define LINUX_T_ALIGN_CHECK 17 |
95 | #define LINUX_T_MACHINE_CHECK 18 /* XXX */ |
96 | #define LINUX_T_SIMD_COPROC_ERROR 19 /* XXX */ |
97 | |
98 | /* Note 255 is bogus */ |
99 | static const int trapno_to_x86_vec[] = { |
100 | LINUX_T_INVALID_OP, /* 0 T_PRIVINFLT */ |
101 | LINUX_T_INT3, /* 1 T_BPTFLT */ |
102 | LINUX_T_COPROC_ERROR, /* 2 T_ARITHTRAP */ |
103 | LINUX_T_SPURIOUS_INTERRUPT, /* 3 T_ASTFLT XXX: ??? */ |
104 | LINUX_T_GENERAL_PROT_FAULT, /* 4 T_PROTFLT */ |
105 | LINUX_T_DEBUG, /* 5 T_TRCTRAP */ |
106 | LINUX_T_PAGE_FAULT, /* 6 T_PAGEFLT */ |
107 | LINUX_T_ALIGN_CHECK, /* 7 T_ALIGNFLT */ |
108 | LINUX_T_DIVIDE, /* 8 T_DIVIDE */ |
109 | LINUX_T_NMI, /* 9 T_NMI */ |
110 | LINUX_T_OVERFLOW, /* 10 T_OFLOW */ |
111 | LINUX_T_BOUNDS, /* 11 T_BOUND */ |
112 | LINUX_T_DEVICE_NOT_AVAIL, /* 12 T_DNA */ |
113 | LINUX_T_DOUBLE_FAULT, /* 13 T_DOUBLEFLT */ |
114 | LINUX_T_COPROC_SEG_OVERRUN, /* 14 T_FPOPFLT */ |
115 | LINUX_T_INVALID_TSS, /* 15 T_TSSFLT */ |
116 | LINUX_T_SEG_NOT_PRESENT, /* 16 T_SEGNPFLT */ |
117 | LINUX_T_STACK_SEG_FAULT, /* 17 T_STKFLT */ |
118 | LINUX_T_MACHINE_CHECK /* 18 T_RESERVED XXX: ??? */ |
119 | }; |
120 | |
121 | /* For the nmi and reserved below linux does not post a signal. */ |
122 | static const int linux_x86_vec_to_sig[] = { |
123 | SIGFPE, /* 0 LINUX_T_DIVIDE */ |
124 | SIGTRAP, /* 1 LINUX_T_DEBUG */ |
125 | /*nmi*/ SIGSEGV, /* 2 LINUX_T_NMI */ |
126 | SIGTRAP, /* 3 LINUX_T_INT3 */ |
127 | SIGSEGV, /* 4 LINUX_T_OVERFLOW */ |
128 | SIGSEGV, /* 5 LINUX_T_BOUNDS */ |
129 | SIGILL, /* 6 LINUX_T_INVALIDOP */ |
130 | SIGSEGV, /* 7 LINUX_T_DEVICE_NOT_AVAIL */ |
131 | SIGSEGV, /* 8 LINUX_T_DOUBLE_FAULT */ |
132 | SIGFPE, /* 9 LINUX_T_COPROC_SEG_OVERRUN */ |
133 | SIGSEGV, /* 10 LINUX_T_INVALID_TSS */ |
134 | SIGBUS, /* 11 LINUX_T_SEG_NOT_PRESENT */ |
135 | SIGBUS, /* 12 LINUX_T_STACK_SEG_FAULT */ |
136 | SIGSEGV, /* 13 LINUX_T_GENERAL_PROT_FAULT */ |
137 | SIGSEGV, /* 14 LINUX_T_PAGE_FAULT */ |
138 | /*resv*/SIGSEGV, /* 15 LINUX_T_SPURIOUS_INTERRUPT */ |
139 | SIGFPE, /* 16 LINUX_T_COPROC_ERROR */ |
140 | SIGSEGV, /* 17 LINUX_T_ALIGN_CHECK */ |
141 | SIGSEGV /* 18 LINUX_T_MACHINE_CHECK */ |
142 | }; |
143 | |
144 | void |
145 | linux_trapsignal(struct lwp *l, ksiginfo_t *ksi) |
146 | { |
147 | ksiginfo_t nksi; |
148 | |
149 | switch (ksi->ksi_signo) { |
150 | case SIGILL: |
151 | case SIGTRAP: |
152 | case SIGIOT: |
153 | case SIGBUS: |
154 | case SIGFPE: |
155 | case SIGSEGV: |
156 | KASSERT(KSI_TRAP_P(ksi)); |
157 | if (ksi->ksi_trap < __arraycount(trapno_to_x86_vec)) { |
158 | nksi = *ksi; |
159 | nksi.ksi_trap = trapno_to_x86_vec[ksi->ksi_trap]; |
160 | if (nksi.ksi_trap < __arraycount(linux_x86_vec_to_sig)) { |
161 | nksi.ksi_signo |
162 | = linux_x86_vec_to_sig[nksi.ksi_trap]; |
163 | } else { |
164 | uprintf("Unhandled sig type %d\n" , |
165 | ksi->ksi_trap); |
166 | } |
167 | ksi = &nksi; |
168 | } else { |
169 | uprintf("Unhandled trap type %d\n" , ksi->ksi_trap); |
170 | } |
171 | /*FALLTHROUGH*/ |
172 | |
173 | default: |
174 | trapsignal(l, ksi); |
175 | return; |
176 | } |
177 | } |
178 | |
179 | int |
180 | linux_lwp_setprivate(struct lwp *l, void *ptr) |
181 | { |
182 | struct linux_user_desc info; |
183 | int error; |
184 | |
185 | #ifdef __x86_64__ |
186 | if ((l->l_proc->p_flag & PK_32) == 0) { |
187 | return lwp_setprivate(l, ptr); |
188 | } |
189 | #endif |
190 | error = copyin(ptr, &info, sizeof(info)); |
191 | if (error) |
192 | return error; |
193 | |
194 | DPRINTF(("linux_lwp_setprivate: %i, %x, %x, %i, %i, %i, %i, %i, %i\n" , |
195 | info.entry_number, info.base_addr, info.limit, info.seg_32bit, |
196 | info.contents, info.read_exec_only, info.limit_in_pages, |
197 | info.seg_not_present, info.useable)); |
198 | |
199 | if (info.entry_number != GUGS_SEL) { |
200 | info.entry_number = GUGS_SEL; |
201 | error = copyout(&info, ptr, sizeof(info)); |
202 | if (error) |
203 | return error; |
204 | } |
205 | return lwp_setprivate(l, (void *)(uintptr_t)info.base_addr); |
206 | } |
207 | |