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