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
linux_trapsignal(struct lwp * l,ksiginfo_t * ksi)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
linux_lwp_setprivate(struct lwp * l,void * ptr)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