1 /*
2 * (c) 2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
3 * Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
5 * This file is part of TUD:OS and distributed under the terms of the
6 * GNU Lesser General Public License 2.1.
7 * Please see the COPYING-LGPL-2.1 file for details.
8 */
9
10 #include <l4/sys/thread>
11 #include <l4/sys/debugger.h>
12 #include <l4/sys/exception>
13 #include <l4/re/env>
14 #include <l4/re/debug>
15 #include <l4/util/util.h>
16 #include <l4/libc_backends/sig.h>
17
18 #include <sys/time.h>
19
20 #include "arch.h"
21
22 #include <errno.h>
23 #include <signal.h>
24 #include <cstdio>
25 #include <unistd.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <pthread-l4.h>
29
30 #include <l4/sys/cxx/ipc_epiface>
31 #include <l4/sys/cxx/ipc_server_loop>
32
33 namespace {
34 struct Sig_handling : L4::Epiface_t<Sig_handling, L4::Exception>
35 {
36 // handlers registered with 'signal'
37 struct sigaction sigactions[_NSIG];
38
39 L4::Cap<L4::Thread> thcap;
40 pthread_t pthread;
41
42 struct itimerval current_itimerval;
43 l4_cpu_time_t alarm_timeout;
44
45 Sig_handling();
46
47 void ping_exc_handler();
48 l4_addr_t get_handler(int signum);
49 int get_any_async_handler();
50 bool is_async_sig(int sig);
51 sighandler_t signal(int signum, sighandler_t handler) throw();
52 int sigaction(int signum, const struct sigaction *act,
53 struct sigaction *oldact) throw();
54 int setitimer(__itimer_which_t __which,
55 __const struct itimerval *__restrict __new,
56 struct itimerval *__restrict __old) throw();
57
58 public:
59 int op_exception(L4::Exception::Rights, l4_exc_regs_t &exc,
60 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &);
61 };
62
63 }
64
65 // -----------------------------------------------------------------------
66
67
68 l4_addr_t
get_handler(int signum)69 Sig_handling::get_handler(int signum)
70 {
71 if (signum >= _NSIG)
72 return 0;
73 if ( (sigactions[signum].sa_flags & SA_SIGINFO)
74 && sigactions[signum].sa_sigaction)
75 return (l4_addr_t)sigactions[signum].sa_sigaction;
76 else if (sigactions[signum].sa_handler)
77 return (l4_addr_t)sigactions[signum].sa_handler;
78 return 0;
79 }
80
81 bool
is_async_sig(int sig)82 Sig_handling::is_async_sig(int sig)
83 {
84 switch (sig)
85 {
86 case SIGALRM:
87 case SIGHUP:
88 case SIGUSR1:
89 case SIGUSR2:
90 case SIGWINCH:
91 case SIGPWR:
92 case SIGXCPU:
93 case SIGSYS: return true;
94 default: return false;
95 };
96 }
97
98 int
get_any_async_handler()99 Sig_handling::get_any_async_handler()
100 {
101 for (int i = 0; i < _NSIG; ++i)
102 if (is_async_sig(i) && get_handler(i))
103 return i;
104 return 0;
105 }
106
107 asm(
108 ".text \n\t"
109 ".global libc_be_sig_return_trap \n\t"
110 "libc_be_sig_return_trap: \n\t"
111 #if defined(ARCH_x86) || defined(ARCH_amd64)
112 " ud2a \n\t"
113 #elif defined(ARCH_arm)
114 ".p2align 2 \n\t"
115 "word: .long 0xe1600070 \n\t" // smc
116 #elif defined(ARCH_arm64)
117 ".p2align 2 \n\t"
118 "brk #123 \n\t"
119 #elif defined(ARCH_ppc32)
120 "trap \n\t"
121 #elif defined(ARCH_sparc)
122 "ta 0x1 \n\t"
123 #elif defined(ARCH_mips)
124 ".long 0x04170010 # sigrie 0x10 \n\t"
125 #else
126 #error Unsupported arch!
127 #endif
128 ".previous \n\t"
129 );
130
131 extern char libc_be_sig_return_trap[];
132
range_ok(l4_addr_t start,unsigned long size)133 static bool range_ok(l4_addr_t start, unsigned long size)
134 {
135 L4Re::Rm::Offset offset;
136 L4Re::Rm::Flags flags;
137 L4::Cap<L4Re::Dataspace> ds;
138
139 return !L4Re::Env::env()->rm()->find(&start, &size, &offset, &flags, &ds)
140 && (flags.w());
141 }
142
dump_rm()143 static void dump_rm()
144 {
145 L4::Cap<L4Re::Debug_obj> d(L4Re::Env::env()->rm().cap());
146 d->debug(0);
147 }
148
setup_sig_frame(l4_exc_regs_t * u,int signum)149 static bool setup_sig_frame(l4_exc_regs_t *u, int signum)
150 {
151 #if defined(ARCH_mips)
152 // put state + pointer to it on stack
153 ucontext_t *ucf = (ucontext_t *)(u->r[29] - sizeof(*ucf));
154 #else
155 // put state + pointer to it on stack
156 ucontext_t *ucf = (ucontext_t *)(u->sp - sizeof(*ucf));
157 #endif
158
159 /* Check if memory access is fine */
160 if (!range_ok((l4_addr_t)ucf, sizeof(*ucf)))
161 return false;
162
163 fill_ucontext_frame(ucf, u);
164
165 #ifdef ARCH_arm
166 u->sp = (l4_umword_t)ucf;
167 u->r[0] = signum;
168 u->r[1] = 0; // siginfo_t pointer, we do not have one right currently
169 u->r[2] = (l4_umword_t)ucf;
170 u->ulr = (unsigned long)libc_be_sig_return_trap;
171 #elif defined(ARCH_mips)
172 u->r[29] = (l4_umword_t)ucf;
173 u->r[0] = signum;
174 u->r[1] = 0; // siginfo_t pointer, we do not have one right currently
175 u->r[2] = (l4_umword_t)ucf;
176 u->epc = (unsigned long)libc_be_sig_return_trap;
177 #else
178 u->sp = (l4_umword_t)ucf - sizeof(void *);
179 *(l4_umword_t *)u->sp = (l4_umword_t)ucf;
180
181 // siginfo_t pointer, we do not have one right currently
182 u->sp -= sizeof(siginfo_t *);
183 *(l4_umword_t *)u->sp = 0;
184
185 // both types get the signum as the first argument
186 u->sp -= sizeof(l4_umword_t);
187 *(l4_umword_t *)u->sp = signum;
188
189 u->sp -= sizeof(l4_umword_t);
190 *(unsigned long *)u->sp = (unsigned long)libc_be_sig_return_trap;
191 #endif
192
193 return true;
194 }
195
op_exception(L4::Exception::Rights,l4_exc_regs_t & exc,L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)196 int Sig_handling::op_exception(L4::Exception::Rights, l4_exc_regs_t &exc,
197 L4::Ipc::Opt<L4::Ipc::Snd_fpage> &)
198 {
199 l4_addr_t handler;
200 l4_exc_regs_t _u = exc;
201 l4_exc_regs_t *const u = &_u;
202 int pc_delta = 0;
203
204 #if defined(ARCH_arm) || defined(ARCH_mips)
205 pc_delta = -4;
206 #endif
207
208 #if defined(ARCH_arm) || defined(ARCH_arm64)
209 if ((u->err >> 26) == 0x3e)
210 #elif defined(ARCH_mips)
211 if ((u->cause & 0x1ff) == 0x101)
212 #elif defined(ARCH_ppc32)
213 if ((u->err & 3) == 4)
214 #else
215 if (u->trapno == 0xff)
216 #endif
217 {
218 //printf("SIGALRM\n");
219
220 int sig = get_any_async_handler();
221
222 if (sig == 0)
223 {
224 printf("No signal handler found\n");
225 return -L4_ENOREPLY;
226 }
227
228 if ( !(handler = get_handler(sig))
229 || !setup_sig_frame(u, sig))
230 {
231 printf("Invalid user memory for sigframe...\n");
232 return -L4_ENOREPLY;
233 }
234
235
236 l4_utcb_exc_pc_set(u, handler);
237 exc = _u; // expensive? how to set amount of words in tag without copy?
238 return -L4_EOK;
239 }
240
241 // x86: trap6
242 if (l4_utcb_exc_pc(u) + pc_delta == (l4_addr_t)libc_be_sig_return_trap)
243 {
244 // sig-return
245 //printf("Sigreturn\n");
246
247 #if defined(ARCH_arm)
248 ucontext_t *ucf = (ucontext_t *)u->sp;
249 #elif defined(ARCH_mips)
250 ucontext_t *ucf = (ucontext_t *)u->r[29];
251 #else
252 ucontext_t *ucf = (ucontext_t *)(u->sp + sizeof(l4_umword_t) * 3);
253 #endif
254
255 if (!range_ok((l4_addr_t)ucf, sizeof(*ucf)))
256 {
257 dump_rm();
258 printf("Invalid memory...\n");
259 return -L4_ENOREPLY;
260 }
261
262 fill_utcb_exc(u, ucf);
263
264 //show_regs(u);
265
266 exc = _u; // expensive? how to set amount of words in tag without copy?
267 return -L4_EOK;
268 }
269
270 if (!(handler = get_handler(SIGSEGV)))
271 {
272 printf("No signal handler found\n");
273 return -L4_ENOREPLY;
274 }
275
276
277 printf("Doing SIGSEGV\n");
278
279 if (!setup_sig_frame(u, SIGSEGV))
280 {
281 printf("Invalid user memory for sigframe...\n");
282 return -L4_ENOREPLY;
283 }
284
285 show_regs(u);
286
287 l4_utcb_exc_pc_set(u, handler);
288 exc = _u; // expensive? how to set amount of words in tag without copy?
289
290 //printf("and back\n");
291 return -L4_EOK;
292 }
293
294 static Sig_handling _sig_handling;
295
296 namespace {
297
298 struct Loop_hooks :
299 public L4::Ipc_svr::Compound_reply,
300 public L4::Ipc_svr::Default_setup_wait
301 {
timeout__anon90c359230211::Loop_hooks302 static l4_timeout_t timeout()
303 {
304 if (_sig_handling.alarm_timeout)
305 {
306 l4_timeout_t t;
307 l4_rcv_timeout(l4_timeout_abs(_sig_handling.alarm_timeout, 1), &t);
308 _sig_handling.alarm_timeout = 0;
309 return t;
310 }
311
312 if (_sig_handling.current_itimerval.it_value.tv_sec == 0
313 && _sig_handling.current_itimerval.it_value.tv_usec == 0)
314 return L4_IPC_NEVER;
315 return l4_timeout(L4_IPC_TIMEOUT_NEVER,
316 l4util_micros2l4to(_sig_handling.current_itimerval.it_value.tv_sec * 1000000 +
317 _sig_handling.current_itimerval.it_value.tv_usec));
318 }
319
error__anon90c359230211::Loop_hooks320 void error(l4_msgtag_t res, l4_utcb_t *utcb)
321 {
322 long ipc_error = l4_ipc_error(res, utcb);
323
324 if (ipc_error == L4_IPC_RETIMEOUT)
325 {
326 l4_msgtag_t t;
327
328 // any thread is ok, right?!
329 t = L4Re::Env::env()->main_thread()
330 ->ex_regs(~0UL, ~0UL,
331 L4_THREAD_EX_REGS_TRIGGER_EXCEPTION);
332 if (l4_error(t))
333 printf("ex_regs error\n");
334
335
336
337 // reload
338 _sig_handling.current_itimerval.it_value = _sig_handling.current_itimerval.it_interval;
339
340 return;
341 }
342 printf("(unsupported/strange) loopabort: %lx\n", ipc_error);
343 }
344 };
345
346
__handler_main(void *)347 static void *__handler_main(void *)
348 {
349 L4::Server<Loop_hooks> srv;
350 srv.loop_noexc(&_sig_handling);
351 return 0;
352 }
353 }
354
Sig_handling()355 Sig_handling::Sig_handling()
356 {
357 if (pthread_create(&pthread, 0, __handler_main, 0))
358 {
359 fprintf(stderr, "libsig: Failed to create handler thread\n");
360 return;
361 }
362
363 thcap = Pthread::L4::cap(pthread);
364
365 l4_debugger_set_object_name(thcap.cap(), "&-");
366
367 libsig_be_add_thread(l4re_env()->main_thread);
368
369 return;
370 }
371
libsig_be_set_dbg_name(const char * n)372 void libsig_be_set_dbg_name(const char *n)
373 {
374 char s[15];
375 snprintf(s, sizeof(s) - 1, "&%s", n);
376 l4_debugger_set_object_name(_sig_handling.thcap.cap(), s);
377 }
378
libsig_be_add_thread(l4_cap_idx_t t)379 void libsig_be_add_thread(l4_cap_idx_t t)
380 {
381 L4::Cap<L4::Thread> tt(t);
382 L4::Thread::Attr a;
383 a.exc_handler(_sig_handling.thcap);
384 if (int e = l4_error(tt->control(a)))
385 fprintf(stderr, "libsig: thread-control error: %d\n", e);
386 //printf("Set exc-handler %lx for %lx\n", thcap.cap(), t);
387 }
388
389 inline
ping_exc_handler()390 void Sig_handling::ping_exc_handler() throw()
391 {
392 l4_ipc_call(thcap.cap(), l4_utcb(), l4_msgtag(0, 0, 0, 0), L4_IPC_NEVER);
393 }
394
395 inline
396 sighandler_t
signal(int signum,sighandler_t handler)397 Sig_handling::signal(int signum, sighandler_t handler) throw()
398 {
399 if (signum < _NSIG)
400 {
401 sighandler_t old = sigactions[signum].sa_handler;
402 sigactions[signum].sa_handler = handler;
403 return old;
404 }
405
406 return SIG_ERR;
407 }
408
409 extern "C"
signal(int signum,sighandler_t handler)410 sighandler_t signal(int signum, sighandler_t handler) L4_NOTHROW
411 {
412 //printf("Called: %s(%d, %p)\n", __func__, signum, handler);
413 return _sig_handling.signal(signum, handler);
414 }
415
416 inline
417 int
sigaction(int signum,const struct sigaction * act,struct sigaction * oldact)418 Sig_handling::sigaction(int signum, const struct sigaction *act,
419 struct sigaction *oldact) throw()
420 {
421 if (signum == SIGKILL || signum == SIGSTOP)
422 return -EINVAL;
423
424 if (signum < _NSIG)
425 {
426 if (oldact)
427 *oldact = sigactions[signum];
428 if (act)
429 sigactions[signum] = *act;
430 return 0;
431 }
432
433 return -EINVAL;
434 }
435
436 extern "C"
sigaction(int signum,const struct sigaction * act,struct sigaction * oldact)437 int sigaction(int signum, const struct sigaction *act,
438 struct sigaction *oldact) L4_NOTHROW
439 {
440 //printf("Called: %s(%d, %p, %p)\n", __func__, signum, act, oldact);
441 int err = _sig_handling.sigaction(signum, act, oldact);
442 if (err < 0)
443 {
444 errno = -err;
445 return -1;
446 }
447
448 return err;
449 }
450
451 extern "C"
sigprocmask(int how,const sigset_t * set,sigset_t * oldset)452 int sigprocmask(int how, const sigset_t *set, sigset_t *oldset) throw()
453 {
454 printf("%s(%d, %p, %p): Unimplemented\n", __func__, how, set, oldset);
455 errno = EINVAL;
456 return -1;
457 }
458
459 extern "C"
sigpending(sigset_t * set)460 int sigpending(sigset_t *set) throw()
461 {
462 printf("%s(%p): Unimplemented\n", __func__, set);
463 errno = EFAULT;
464 return -1;
465 }
466
sigsuspend(const sigset_t * mask)467 int sigsuspend(const sigset_t *mask) throw()
468 {
469 printf("%s(%p): Unimplemented\n", __func__, mask);
470 errno = EFAULT;
471 return -1;
472 }
473
474 extern "C"
killpg(int pgrp,int sig)475 int killpg(int pgrp, int sig) throw()
476 {
477 printf("%s(%d, %d): Unimplemented\n", __func__, pgrp, sig);
478 errno = EPERM;
479 return -1;
480 }
481
482 extern "C"
alarm(unsigned int seconds)483 unsigned int alarm(unsigned int seconds) L4_NOTHROW
484 {
485 //printf("unimplemented: alarm(%u)\n", seconds);
486
487 _sig_handling.alarm_timeout = l4_kip_clock(l4re_kip()) + seconds * 1000000;
488
489 _sig_handling.ping_exc_handler();
490 return 0;
491 }
492
493 extern "C"
wait(void * status)494 pid_t wait(void *status)
495 {
496 printf("unimplemented: wait(%p)\n", status);
497 return -1;
498 }
499
500
501
getitimer(__itimer_which_t __which,struct itimerval * __value)502 int getitimer(__itimer_which_t __which,
503 struct itimerval *__value) L4_NOTHROW
504 {
505 if (__which != ITIMER_REAL)
506 {
507 errno = EINVAL;
508 return -1;
509 }
510
511 *__value = _sig_handling.current_itimerval;
512
513 _sig_handling.ping_exc_handler();
514 return 0;
515 }
516
517 inline
518 int
setitimer(__itimer_which_t __which,__const struct itimerval * __restrict __new,struct itimerval * __restrict __old)519 Sig_handling::setitimer(__itimer_which_t __which,
520 __const struct itimerval *__restrict __new,
521 struct itimerval *__restrict __old) throw()
522 {
523 printf("called %s(..)\n", __func__);
524
525 if (__which != ITIMER_REAL)
526 {
527 errno = EINVAL;
528 return -1;
529 }
530
531 if (__old)
532 *__old = current_itimerval;
533
534 if (__new->it_value.tv_usec < 0
535 || __new->it_value.tv_usec > 999999
536 || __new->it_interval.tv_usec < 0
537 || __new->it_interval.tv_usec > 999999)
538 {
539 errno = EINVAL;
540 return -1;
541 }
542
543 printf("%s: setting stuff\n", __func__);
544 current_itimerval = *__new;
545
546 ping_exc_handler();
547 return 0;
548 }
549
setitimer(__itimer_which_t __which,__const struct itimerval * __restrict __new,struct itimerval * __restrict __old)550 int setitimer(__itimer_which_t __which,
551 __const struct itimerval *__restrict __new,
552 struct itimerval *__restrict __old) L4_NOTHROW
553 {
554 int err = _sig_handling.setitimer(__which, __new, __old);
555 if (err < 0)
556 {
557 errno = -err;
558 return -1;
559 }
560 return 0;
561 }
562