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