trap.c revision 1.3 1 /* $NetBSD: trap.c,v 1.3 2017/08/25 22:23:59 nisimura Exp $ */
2
3 /*-
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Matt Thomas of 3am Software Foundry.
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 #include <sys/cdefs.h>
33
34 __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.3 2017/08/25 22:23:59 nisimura Exp $");
35
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/cpu.h>
39 #include <sys/proc.h>
40 #include <sys/userret.h>
41 #include <sys/systm.h>
42
43 #include <sys/signal.h>
44 #include <sys/signalvar.h>
45 #include <sys/siginfo.h>
46
47 #include <aarch64/locore.h>
48
49 static void
50 dump_trapframe(struct trapframe *tf, void (*pr)(const char *, ...))
51 {
52 (*pr)("trapframe @ %p:\n", tf);
53 (*pr)("esr=%016"PRIxREGISTER
54 ", pc=%016"PRIxREGISTER
55 ", lr=%016"PRIxREGISTER
56 ", sp=%016"PRIxREGISTER"\n",
57 tf->tf_esr, tf->tf_pc, tf->tf_lr, tf->tf_sp);
58 (*pr)(" x0=%016"PRIxREGISTER
59 ", x1=%016"PRIxREGISTER
60 ", x2=%016"PRIxREGISTER
61 ", x3=%016"PRIxREGISTER"\n",
62 tf->tf_reg[0], tf->tf_reg[1], tf->tf_reg[2], tf->tf_reg[3]);
63 (*pr)(" x4=%016"PRIxREGISTER
64 ", x5=%016"PRIxREGISTER
65 ", x6=%016"PRIxREGISTER
66 ", x7=%016"PRIxREGISTER"\n",
67 tf->tf_reg[4], tf->tf_reg[5], tf->tf_reg[6], tf->tf_reg[7]);
68 (*pr)(" x8=%016"PRIxREGISTER
69 ", x9=%016"PRIxREGISTER
70 ", x10=%016"PRIxREGISTER
71 ", x11=%016"PRIxREGISTER"\n",
72 tf->tf_reg[8], tf->tf_reg[9], tf->tf_reg[10], tf->tf_reg[11]);
73 (*pr)("x12=%016"PRIxREGISTER
74 ", x13=%016"PRIxREGISTER
75 ", x14=%016"PRIxREGISTER
76 ", x15=%016"PRIxREGISTER"\n",
77 tf->tf_reg[12], tf->tf_reg[13], tf->tf_reg[14], tf->tf_reg[15]);
78 (*pr)("x16=%016"PRIxREGISTER
79 ", x17=%016"PRIxREGISTER
80 ", x18=%016"PRIxREGISTER
81 ", x19=%016"PRIxREGISTER"\n",
82 tf->tf_reg[16], tf->tf_reg[17], tf->tf_reg[18], tf->tf_reg[19]);
83 (*pr)("x20=%016"PRIxREGISTER
84 ", x21=%016"PRIxREGISTER
85 ", x22=%016"PRIxREGISTER
86 ", x23=%016"PRIxREGISTER"\n",
87 tf->tf_reg[20], tf->tf_reg[21], tf->tf_reg[22], tf->tf_reg[23]);
88 (*pr)("x24=%016"PRIxREGISTER
89 ", x25=%016"PRIxREGISTER
90 ", x26=%016"PRIxREGISTER
91 ", x27=%016"PRIxREGISTER"\n",
92 tf->tf_reg[24], tf->tf_reg[25], tf->tf_reg[26], tf->tf_reg[27]);
93 (*pr)("x28=%016"PRIxREGISTER
94 ", x29=%016"PRIxREGISTER
95 ", x30=%016"PRIxREGISTER"\n",
96 tf->tf_reg[28], tf->tf_reg[29], tf->tf_reg[30]);
97 }
98
99 void
100 userret(struct lwp *l, struct trapframe *tf)
101 {
102 mi_userret(l);
103 }
104
105 void
106 trap(struct trapframe *tf, int reason)
107 {
108 struct lwp * const l = curlwp;
109 size_t code = tf->tf_esr & 0xffff;
110 bool usertrap_p = tf->tf_esr & 01;
111 bool ok = true;
112 ksiginfo_t ksi;
113
114 code = code;
115 dump_trapframe(tf, printf);
116
117 if (usertrap_p) {
118 if (!ok)
119 (*l->l_proc->p_emul->e_trapsignal)(l, &ksi);
120 userret(l, tf);
121 }
122 else if (!ok) {
123 dump_trapframe(tf, printf);
124 panic("%s: fatal kernel trap", __func__);
125 }
126 }
127
128 void
129 interrupt(struct trapframe *tf)
130 {
131 }
132
133 // XXXAARCH64 might be populated in frame.h in future
134
135 #define FB_X19 0
136 #define FB_X20 1
137 #define FB_X21 2
138 #define FB_X22 3
139 #define FB_X23 4
140 #define FB_X24 5
141 #define FB_X25 6
142 #define FB_X26 7
143 #define FB_X27 8
144 #define FB_X28 9
145 #define FB_X29 10
146 #define FB_LR 11
147 #define FB_SP 12
148 #define FB_V0 13
149 #define FB_MAX 14
150
151 struct faultbuf {
152 register_t fb_reg[FB_MAX];
153 };
154
155 int cpu_set_onfault(struct faultbuf *, register_t) __returns_twice;
156 void cpu_jump_onfault(struct trapframe *, const struct faultbuf *);
157 void cpu_unset_onfault(void);
158 struct faultbuf *cpu_disable_onfault(void);
159 void cpu_enable_onfault(struct faultbuf *);
160
161 void
162 cpu_jump_onfault(struct trapframe *tf, const struct faultbuf *fb)
163 {
164
165 tf->tf_reg[19] = fb->fb_reg[FB_X19];
166 tf->tf_reg[20] = fb->fb_reg[FB_X20];
167 tf->tf_reg[21] = fb->fb_reg[FB_X21];
168 tf->tf_reg[22] = fb->fb_reg[FB_X22];
169 tf->tf_reg[23] = fb->fb_reg[FB_X23];
170 tf->tf_reg[24] = fb->fb_reg[FB_X24];
171 tf->tf_reg[25] = fb->fb_reg[FB_X25];
172 tf->tf_reg[26] = fb->fb_reg[FB_X26];
173 tf->tf_reg[27] = fb->fb_reg[FB_X27];
174 tf->tf_reg[28] = fb->fb_reg[FB_X28];
175 tf->tf_reg[29] = fb->fb_reg[FB_X29];
176 tf->tf_reg[0] = fb->fb_reg[FB_V0];
177 tf->tf_sp = fb->fb_reg[FB_SP];
178 tf->tf_lr = fb->fb_reg[FB_LR];
179 }
180
181 void
182 cpu_unset_onfault(void)
183 {
184
185 curlwp->l_md.md_onfault = NULL;
186 }
187
188 struct faultbuf *
189 cpu_disable_onfault(void)
190 {
191 struct faultbuf * const fb = curlwp->l_md.md_onfault;
192
193 curlwp->l_md.md_onfault = NULL;
194 return fb;
195 }
196
197 void
198 cpu_enable_onfault(struct faultbuf *fb)
199 {
200
201 curlwp->l_md.md_onfault = NULL;
202 }
203
204 /*
205 * kcopy(9)
206 * int kcopy(const void *src, void *dst, size_t len);
207 *
208 * copy(9)
209 * int copyin(const void *uaddr, void *kaddr, size_t len);
210 * int copyout(const void *kaddr, void *uaddr, size_t len);
211 * int copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done);
212 * int copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done);
213 * int copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done);
214 */
215
216 int
217 kcopy(const void *kfaddr, void *kdaddr, size_t len)
218 {
219 struct faultbuf fb;
220 int error;
221
222 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
223 memcpy(kdaddr, kfaddr, len);
224 cpu_unset_onfault();
225 }
226 return error;
227 }
228
229 int
230 copyin(const void *uaddr, void *kaddr, size_t len)
231 {
232 struct faultbuf fb;
233 int error;
234
235 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
236 memcpy(kaddr, uaddr, len);
237 cpu_unset_onfault();
238 }
239 return error;
240 }
241
242 int
243 copyout(const void *kaddr, void *uaddr, size_t len)
244 {
245 struct faultbuf fb;
246 int error;
247
248 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
249 memcpy(uaddr, kaddr, len);
250 cpu_unset_onfault();
251 }
252 return error;
253 }
254
255 int
256 copystr(const void *kfaddr, void *kdaddr, size_t len, size_t *done)
257 {
258 struct faultbuf fb;
259 int error;
260
261 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
262 len = strlcpy(kdaddr, kfaddr, len);
263 cpu_unset_onfault();
264 if (done != NULL) {
265 *done = len;
266 }
267 }
268 return error;
269 }
270
271 int
272 copyinstr(const void *uaddr, void *kaddr, size_t len, size_t *done)
273 {
274 struct faultbuf fb;
275 int error;
276
277 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
278 len = strlcpy(kaddr, uaddr, len);
279 cpu_unset_onfault();
280 if (done != NULL) {
281 *done = len;
282 }
283 }
284 return error;
285 }
286
287 int
288 copyoutstr(const void *kaddr, void *uaddr, size_t len, size_t *done)
289 {
290 struct faultbuf fb;
291 int error;
292
293 if ((error = cpu_set_onfault(&fb, EFAULT)) == 0) {
294 len = strlcpy(uaddr, kaddr, len);
295 cpu_unset_onfault();
296 if (done != NULL) {
297 *done = len;
298 }
299 }
300 return error;
301 }
302
303 /*
304 * fetch(9)
305 * int fubyte(const void *base);
306 * int fusword(const void *base);
307 * int fuswintr(const void *base);
308 * long fuword(const void *base);
309 *
310 * store(9)
311 * int subyte(void *base, int c);
312 * int susword(void *base, short c);
313 * int suswintr(void *base, short c);
314 * int suword(void *base, long c);
315 */
316
317 union xubuf {
318 uint8_t b[4];
319 uint16_t w[2];
320 uint32_t l[1];
321 };
322
323 static bool
324 fetch_user_data(union xubuf *xu, const void *base, size_t len)
325 {
326 struct faultbuf fb;
327
328 if (cpu_set_onfault(&fb, 1) == 0) {
329 memcpy(xu->b, base, len);
330 cpu_unset_onfault();
331 return true;
332 }
333 return false;
334 }
335
336 int
337 fubyte(const void *base)
338 {
339 union xubuf xu;
340
341 if (fetch_user_data(&xu, base, sizeof(xu.b[0])))
342 return xu.b[0];
343 return -1;
344 }
345
346 int
347 fusword(const void *base)
348 {
349 union xubuf xu;
350
351 if (fetch_user_data(&xu, base, sizeof(xu.w[0])))
352 return xu.w[0];
353 return -1;
354 }
355
356 int
357 fuswintr(const void *base)
358 {
359
360 return -1;
361 }
362
363 long
364 fuword(const void *base)
365 {
366 union xubuf xu;
367
368 if (fetch_user_data(&xu, base, sizeof(xu.l[0])))
369 return xu.l[0];
370 return -1;
371 }
372
373 static bool
374 store_user_data(void *base, const union xubuf *xu, size_t len)
375 {
376 struct faultbuf fb;
377
378 if (cpu_set_onfault(&fb, 1) == 0) {
379 memcpy(base, xu->b, len);
380 cpu_unset_onfault();
381 return true;
382 }
383 return false;
384 }
385
386 int
387 subyte(void *base, int c)
388 {
389 union xubuf xu;
390
391 xu.l[0] = 0; xu.b[0] = c; // { .b[0] = c, .b[1 ... 3] = 0 }
392 return store_user_data(base, &xu, sizeof(xu.b[0])) ? 0 : -1;
393 }
394
395 int
396 susword(void *base, short c)
397 {
398 union xubuf xu;
399
400 xu.l[0] = 0; xu.w[0] = c; // { .w[0] = c, .w[1] = 0 }
401 return store_user_data(base, &xu, sizeof(xu.w[0])) ? 0 : -1;
402 }
403
404 int
405 suswintr(void *base, short c)
406 {
407
408 return -1;
409 }
410
411 int
412 suword(void *base, long c)
413 {
414 union xubuf xu;
415
416 xu.l[0] = c; // { .l[0] = c }
417 return store_user_data(base, &xu, sizeof(xu.l[0])) ? 0 : -1;
418 }
419