]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/plr/server/src/fault_handlers/syscalls.cc
Update
[l4.git] / l4 / pkg / plr / server / src / fault_handlers / syscalls.cc
1 /*
2  * syscalls.cc --
3  *
4  *     Implementation of Romain syscall handling.
5  *
6  * (c) 2011-2013 Björn Döbel <doebel@os.inf.tu-dresden.de>,
7  *     economic rights: Technische Universität Dresden (Germany)
8  * This file is part of TUD:OS and distributed under the terms of the
9  * GNU General Public License 2.
10  * Please see the COPYING-GPL-2 file for details.
11  */
12
13 #include "../log"
14 #include "../app_loading"
15 #include "../locking.h"
16 #include "../manager"
17 #include "../thread_group.h"
18
19 #include "observers.h"
20
21 #include <l4/re/rm-sys.h>
22 #include <l4/re/util/region_mapping_svr>
23 #include <l4/sys/segment.h>
24 #include <l4/sys/consts.h>
25 #include <l4/cxx/ipc_stream>
26
27 #define MSG() DEBUGf(Romain::Log::Faults)
28 #define MSGt(t) DEBUGf(Romain::Log::Faults) << "[" << t->vcpu() << "] "
29 #define DEBUGt(t) DEBUG() <<  "[" << t->vcpu() << "] "
30
31 #include "syscalls_factory.h" // uses MSG() defined above (ugly)
32
33 DEFINE_EMPTY_STARTUP(SyscallObserver)
34
35 static l4_umword_t num_syscalls;
36
37
38 void Romain::SyscallObserver::status() const
39 {
40         INFO() << "[sys ] System call count: " << num_syscalls;
41 }
42
43
44 static Romain::ThreadHandler          threadsyscall;
45 static Romain::SyscallHandler         nullhandler;
46 static Romain::RegionManagingHandler  rm;
47 static Romain::Scheduling             sched;
48 static Romain::IrqHandler             irq;
49 static Romain::IrqSenderHandler       irq_sender;
50
51 Romain::Factory theObjectFactory;
52
53 Romain::Observer::ObserverReturnVal
54 Romain::SyscallObserver::notify(Romain::App_instance *i,
55                                 Romain::App_thread *t,
56                                 Romain::Thread_group *tg,
57                                 Romain::App_model *a)
58 {
59         enum { Syscall_magic_address = 0xEACFF003, };
60         Romain::Observer::ObserverReturnVal retval = Romain::Observer::Ignored;
61
62         if (t->vcpu()->r()->trapno != 13) {
63                 return retval;
64         }
65
66         /* SYSENTER / INT30 */
67         if (t->vcpu()->r()->ip == Syscall_magic_address) {
68 #if BENCHMARKING
69         unsigned long long t1, t2;
70         t1 = l4_rdtsc();
71 #endif
72                 ++num_syscalls;
73
74                 l4_msgtag_t *tag = reinterpret_cast<l4_msgtag_t*>(&t->vcpu()->r()->ax);
75                 MSG() << "SYSENTER(" << tg->name << ") tag = " << std::hex << tag->label();
76
77 #if EVENT_LOGGING
78                 Measurements::GenericEvent* ev = Romain::globalLogBuf->next();
79                 ev->header.tsc     = Romain::globalLogBuf->getTime(Log::logLocalTSC);
80                 ev->header.vcpu    = (l4_uint32_t)t->vcpu();
81                 ev->header.type    = Measurements::Syscall;
82                 ev->data.sys.eip   = t->vcpu()->r()->bx;
83                 ev->data.sys.label = tag->label();
84 #endif
85
86                 /*
87                  * Fiasco-specific:
88                  *      EBX is return address
89                  *      EBP is return ESP
90                  * -> we need to remember these
91                  */
92                 l4_addr_t ebx_pre = t->vcpu()->r()->bx;
93                 l4_addr_t ebp_pre = t->vcpu()->r()->bp;
94
95                 switch(tag->label()) {
96
97                         case L4_PROTO_NONE:
98                                 /*
99                                  * Catch the open_wait versions of IPC as they require
100                                  * redirection through the gateagent thread. Open wait
101                                  * is defined by the IPC bindings as one where EDX is set
102                                  * to L4_INVALID_CAP | <some_flags>.
103                                  */
104                                 if ((t->vcpu()->r()->dx & L4_INVALID_CAP) == L4_INVALID_CAP) {
105                                         tg->gateagent->trigger_agent(t);
106                                 } else {
107                                         nullhandler.proxy_syscall(i, t, tg, a);
108                                 }
109                                 retval = Romain::Observer::Replicatable;
110                                 break;
111
112                         case L4_PROTO_FACTORY:
113                                 retval = theObjectFactory.handle(i, t, tg, a);
114                                 break;
115
116                         case L4_PROTO_IRQ:
117                                 retval = irq.handle(i, t, tg, a);
118                                 break;
119
120                         case L4_PROTO_IRQ_SENDER:
121                                 retval = irq_sender.handle(i, t, tg, a);
122                                 break;
123
124                         case L4_PROTO_THREAD:
125                                 /* 
126                                  * Each instance needs to perform its own
127                                  * thread creation.
128                                  */
129                                 retval = threadsyscall.handle(i, t, tg, a);
130                                 break;
131
132                         case L4_PROTO_TASK:
133                                 if ((t->vcpu()->r()->dx & ~0xF) == L4RE_THIS_TASK_CAP) {
134                                         retval = handle_task(i, t, a);
135                                 } else {
136                                         nullhandler.proxy_syscall(i, t, tg, a);
137                                         retval = Romain::Observer::Replicatable;
138                                 }
139                                 break;
140
141                         case L4Re::Rm::Protocol:
142                                 /*
143                                  * Region management is done only once as e.g.,
144                                  * regions for attaching need to be replicated
145                                  * across instances. The real adaptation then
146                                  * happens during page fault handling.
147                                  */
148                                 retval = rm.handle(i, t, tg, a);
149                                 break;
150
151                         case L4Re::Parent::Protocol:
152                                 /*
153                                  * The parent protocol is only used for exitting.
154                                  */
155                                 {
156                                         struct timeval tv;
157                                         gettimeofday(&tv, 0);
158                                         INFO() << "Instance " << i->id() << " exitting. Time "
159                                                << YELLOW << tv.tv_sec << "." << tv.tv_usec
160                                                << NOCOLOR;
161
162 #if EVENT_LOGGING
163                                         Measurements::GenericEvent* ev = Romain::globalLogBuf->next();
164                                         ev->header.tsc                 = Romain::globalLogBuf->getTime(Log::logLocalTSC);
165                                         ev->header.vcpu                = (l4_uint32_t)t->vcpu();
166                                         ev->header.type                = Measurements::Thread_stop;
167 #endif
168
169                                         Romain::_the_instance_manager->show_stats();
170                                         
171                                         if (REBOOT_ON_EXIT) enter_kdebug("*#^");
172                                         else exit(0);
173
174                                         nullhandler.proxy_syscall(i, t, tg, a);
175                                         retval = Romain::Observer::Replicatable;
176                                 }
177                                 break;
178
179                         case L4_PROTO_SCHEDULER:
180                                 retval = sched.handle(i, t, tg, a);
181                                 break;
182
183                         default:
184                                 /*
185                                  * Proxied syscalls are always only executed
186                                  * once because for the outside world it must
187                                  * look as if the master server _is_ the one
188                                  * application everyone is talking to.
189                                  */
190                                 nullhandler.proxy_syscall(i, t, tg, a);
191                                 retval = Romain::Observer::Replicatable;
192                                 break;
193                 
194                 }
195
196                 t->vcpu()->r()->ip = ebx_pre;
197                 t->vcpu()->r()->sp = ebp_pre;
198
199 #if BENCHMARKING
200         t2 = l4_rdtsc();
201         t->count_syscalls(t2-t1);
202 #endif
203         } else if (t->vcpu()->r()->err == 0x192) {
204                 // INT 0x32 - debug syste call. We currently ignore it.
205                 t->vcpu()->r()->ip += 2;
206                 retval = Romain::Observer::Replicatable;
207         } else if (t->vcpu()->r()->err == 0x148) { // INT $41 -- NOOP syscall
208                 t->vcpu()->r()->ip += 2;
209                 Romain::Log::logFlags = Romain::Log::All;
210                 retval = Romain::Observer::Replicatable;
211         } else if (t->vcpu()->r()->err == 0x152) { // INT $42 -- enable logging
212                 INFO() << "[" << std::hex << (l4_umword_t)t->vcpu() <<  "] INT 42 ("
213                            << t->vcpu()->r()->ip << ")";
214                 t->vcpu()->print_state();
215                 t->vcpu()->r()->ip += 2;
216                 Romain::Log::logFlags = Romain::Log::All;
217                 retval = Romain::Observer::Replicatable;
218         } else {
219                 t->vcpu()->print_state();
220                 INFO() << "err = " << std::hex << t->vcpu()->r()->err;
221                 enter_kdebug("GPF in replica");
222         }
223
224         return retval;
225 }
226
227
228 void Romain::SyscallHandler::proxy_syscall(Romain::App_instance *,
229                                            Romain::App_thread* t,
230                                            Romain::Thread_group* tg,
231                                            Romain::App_model *)
232 {
233         char backup_utcb[L4_UTCB_OFFSET]; // for storing local UTCB content
234
235         l4_utcb_t *addr = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
236         l4_utcb_t *cur_utcb = l4_utcb();
237         MSGt(t) << "UTCB @ " << std::hex << (l4_umword_t)addr;
238         _check((l4_addr_t)addr == ~0UL, "remote utcb ptr??");
239
240         /*
241          * We are going to perform the system call on behalf of the client. This will
242          * thrash our local UTCB, so we want to store it here.
243          */
244         store_utcb((char*)cur_utcb, backup_utcb);
245         store_utcb((char*)addr, (char*)cur_utcb);
246
247         //t->print_vcpu_state();
248         //Romain::dump_mem((l4_umword_t*)addr, 40);
249
250         /* Perform Fiasco system call */
251         asm volatile (L4_ENTER_KERNEL
252                       : "=a" (t->vcpu()->r()->ax),
253                       "=b" (t->vcpu()->r()->bx),
254                       /* ECX, EDX are overwritten anyway */
255                       "=S" (t->vcpu()->r()->si),
256                       "=D" (t->vcpu()->r()->di)
257                       : "a" (t->vcpu()->r()->ax),
258                       /* EBX and EBP will be overwritten with local
259                        * values in L4_ENTER_KERNEL */
260                         "c" (t->vcpu()->r()->cx),
261                         "d" (t->vcpu()->r()->dx),
262                         "S" (t->vcpu()->r()->si),
263                         "D" (t->vcpu()->r()->di)
264                       : "memory", "cc"
265         );
266
267         /*
268          * Restore my UTCB
269          */
270         store_utcb((char*)cur_utcb, (char*)addr);
271         store_utcb(backup_utcb, (char*)cur_utcb);
272
273         //t->print_vcpu_state();
274         //Romain::dump_mem((l4_umword_t*)addr, 40);
275         //enter_kdebug("done syscall");
276 }
277
278
279 Romain::Observer::ObserverReturnVal
280 Romain::RegionManagingHandler::handle(Romain::App_instance* i,
281                                       Romain::App_thread* t,
282                                       Romain::Thread_group* tg,
283                                       Romain::App_model * a)
284 {
285         MSGt(t) << "RM PROTOCOL";
286
287         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
288         MSGt(t) << "UTCB @ " << std::hex << (l4_umword_t)utcb;
289         _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
290
291         //t->print_vcpu_state();
292         //Romain::dump_mem((l4_umword_t*)utcb, 40, 4);
293
294         {
295                 Romain::Rm_guard r(a->rm(), i->id());
296                 L4::Ipc::Iostream ios(utcb);
297                 L4Re::Util::region_map_server<Romain::Region_map_server>((void*)0, a->rm(), ios);
298                 t->vcpu()->r()->ax = 0;
299         }
300
301         //t->print_vcpu_state();
302         //Romain::dump_mem((l4_umword_t*)utcb, 40);
303
304         return Romain::Observer::Replicatable;
305 }
306
307
308 Romain::Observer::ObserverReturnVal
309 Romain::ThreadHandler::handle(Romain::App_instance *i,
310                               Romain::App_thread* t,
311                               Romain::Thread_group * tg,
312                               Romain::App_model *am)
313 {
314         MSGt(t) << "Thread system call";
315         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
316         MSGt(t) << "UTCB @ " << std::hex << (l4_umword_t)utcb;
317         _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
318
319         //t->print_vcpu_state();
320         //Romain::dump_mem((l4_umword_t*)utcb, 40);
321
322         l4_umword_t op   = l4_utcb_mr_u(utcb)->mr[0] & L4_THREAD_OPCODE_MASK;
323         l4_umword_t dest = t->vcpu()->r()->dx & L4_CAP_MASK;
324
325         DEBUG() << "dest cap " << std::hex << dest << " " << L4_INVALID_CAP;
326         Romain::Thread_group* group = (Romain::Thread_group*)0xdeadbeef;
327         if (dest == L4_INVALID_CAP) {
328                 group = tg;
329         } else {
330                 group = theObjectFactory.thread_for_cap(dest >> L4_CAP_SHIFT);
331         }
332         DEBUG() << "tgroup " << group;
333
334         switch(op) {
335                 case L4_THREAD_CONTROL_OP:
336                         group->control(t, utcb, am);
337                         return Romain::Observer::Replicatable;
338                 case L4_THREAD_EX_REGS_OP:
339                         group->ex_regs(t);
340                         break;
341                 case L4_THREAD_SWITCH_OP:
342                         enter_kdebug("THREAD: switch");
343                         break;
344                 case L4_THREAD_STATS_OP:
345                         enter_kdebug("THREAD: stats");
346                         break;
347                 case L4_THREAD_VCPU_RESUME_OP:
348                         enter_kdebug("THREAD: vcpu_resume");
349                         break;
350                 case L4_THREAD_REGISTER_DELETE_IRQ_OP:
351                         enter_kdebug("THREAD: irq");
352                         break;
353                 case L4_THREAD_MODIFY_SENDER_OP:
354                         enter_kdebug("THREAD: modify sender");
355                         break;
356                 case L4_THREAD_VCPU_CONTROL_OP:
357                         enter_kdebug("THREAD: vcpu control");
358                         break;
359                 case L4_THREAD_VCPU_CONTROL_EXT_OP:
360                         enter_kdebug("THREAD: vcpu control ext");
361                         break;
362                 case L4_THREAD_X86_GDT_OP:
363                         group->gdt(t, utcb);
364                         break;
365                 default:
366                         ERROR() << "unknown thread op: " << std::hex << op << "\n";
367                         break;
368         }
369
370         return Romain::Observer::Replicatable;
371         //enter_kdebug("thread");
372 }
373
374
375 Romain::Observer::ObserverReturnVal
376 Romain::SyscallObserver::handle_task(Romain::App_instance* i,
377                                           Romain::App_thread*   t,
378                                           Romain::App_model*    a)
379 {
380         l4_utcb_t   *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
381         l4_umword_t    op = l4_utcb_mr_u(utcb)->mr[0] & L4_THREAD_OPCODE_MASK;
382         Romain::Observer::ObserverReturnVal ret = Romain::Observer::Finished;
383
384         switch(op) {
385                 case L4_TASK_UNMAP_OP:
386                         {
387                                 l4_fpage_t fp;
388                                 fp.raw = l4_utcb_mr_u(utcb)->mr[2];
389                                 MSGt(t) << "Task::unmap(p = " << std::hex
390                                         << l4_fpage_page(fp) << ", sz = " << l4_fpage_size(fp) << ")";
391                                 i->vcpu_task()->unmap(fp, L4_FP_ALL_SPACES, utcb);
392                         }
393                         //t->vcpu()->r()->ax = 0;
394                         break;
395                 case L4_TASK_CAP_INFO_OP:
396                         nullhandler.proxy_syscall(i,t,0,a);
397                         break;
398                 default:
399                         MSGt(t) << "Task system call";
400                         MSGt(t) << "UTCB @ " << std::hex << (l4_umword_t)utcb << " op: " << op
401                                   << " cap " << (t->vcpu()->r()->dx & ~0xF) << " " << L4RE_THIS_TASK_CAP;
402                         t->print_vcpu_state();
403                         enter_kdebug("unknown task op?");
404                         break;
405         }
406
407         return ret;
408 }
409
410
411 Romain::Observer::ObserverReturnVal
412 Romain::Factory::handle(Romain::App_instance* inst,
413                         Romain::App_thread* t,
414                         Romain::Thread_group* tg,
415                         Romain::App_model* am)
416 {
417         MSGt(t) << "Factory system call";
418         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
419         MSGt(t) << "UTCB @ " << std::hex << (l4_umword_t)utcb;
420         _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
421
422         l4_mword_t obj = l4_utcb_mr_u(utcb)->mr[0];
423         l4_umword_t cap = l4_utcb_br_u(utcb)->br[0] & ~L4_RCV_ITEM_SINGLE_CAP;
424         MSGt(t) << std::hex << L4_PROTO_THREAD;
425         MSGt(t) << "object type: " << std::hex << obj
426               << " cap: " << cap;
427
428         switch(obj) {
429                 case L4_PROTO_THREAD:
430                         create_thread(inst, t, tg, am, cap);
431                         return Romain::Observer::Replicatable;
432
433                 case L4_PROTO_IRQ:
434                         create_irq(inst, t, tg, am, cap);
435                         return Romain::Observer::Replicatable;
436
437                 case L4Re::Dataspace::Protocol:
438                         {
439                         SyscallHandler::proxy_syscall(inst, t, tg, am);
440                         return Romain::Observer::Replicatable;
441                         }
442
443                 default:
444                         break;
445         }
446
447         enter_kdebug("theObjectFactory");
448         return Romain::Observer::Finished;
449 }
450
451
452 Romain::Observer::ObserverReturnVal
453 Romain::Scheduling::handle(Romain::App_instance* inst,
454                            Romain::App_thread* t,
455                            Romain::Thread_group* tg,
456                            Romain::App_model* am)
457 {
458         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
459         l4_umword_t op  = l4_utcb_mr_u(utcb)->mr[0];
460
461         MSGt(t) << "\033[32mschedule(" << std::hex << op << ")\033[0m";
462         if (op == L4_SCHEDULER_RUN_THREAD_OP) {
463                 l4_umword_t cap             = l4_utcb_mr_u(utcb)->mr[6] >> L4_CAP_SHIFT;
464                 Romain::Thread_group* group = theObjectFactory.thread_for_cap(cap);
465                 group->scheduler_run(t);
466         } else {
467                 //enter_kdebug("run_thread != 1");
468                 SyscallHandler::proxy_syscall(inst, t, tg, am);
469         }
470
471         return Romain::Observer::Replicatable;
472 }
473
474
475 Romain::Observer::ObserverReturnVal
476 Romain::IrqHandler::handle(Romain::App_instance* inst,
477                            Romain::App_thread* t,
478                            Romain::Thread_group* tg,
479                            Romain::App_model* am)
480 {
481         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
482         l4_umword_t op     = l4_utcb_mr_u(utcb)->mr[0];
483         l4_umword_t label  = l4_utcb_mr_u(utcb)->mr[1];
484         l4_umword_t cap    = t->vcpu()->r()->dx & L4_CAP_MASK;
485
486         L4::Cap<L4::Irq> irq(cap);
487
488         DEBUGt(t) << "IRQ: cap = " << std::hex << cap << " op = " << op; 
489
490         if (!theObjectFactory.is_irq(cap)) {
491                 SyscallHandler::proxy_syscall(inst, t, tg, am);
492                 return Romain::Observer::Replicatable;
493         }
494
495         switch(op) {
496                 case L4_IRQ_OP_TRIGGER:
497                         DEBUGt(t) << ":: trigger";
498                         //enter_kdebug("trigger");
499                         irq->trigger();
500                         break;
501                 case L4_IRQ_OP_EOI:
502                         DEBUGt(t) << ":: eoi";
503                         tg->gateagent->trigger_agent(t);
504                         break;
505         }
506
507         return Romain::Observer::Replicatable;
508 }
509 Romain::Observer::ObserverReturnVal
510 Romain::IrqSenderHandler::handle(Romain::App_instance* inst,
511                                  Romain::App_thread* t,
512                                  Romain::Thread_group* tg,
513                                  Romain::App_model* am)
514 {
515         l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
516         l4_umword_t op     = l4_utcb_mr_u(utcb)->mr[0];
517         l4_umword_t label  = l4_utcb_mr_u(utcb)->mr[1];
518         l4_umword_t cap    = t->vcpu()->r()->dx & L4_CAP_MASK;
519
520         L4::Cap<L4::Irq> irq(cap);
521
522         DEBUGt(t) << "IRQ: cap = " << std::hex << cap << " op = " << op; 
523
524         if (!theObjectFactory.is_irq(cap)) {
525                 SyscallHandler::proxy_syscall(inst, t, tg, am);
526                 return Romain::Observer::Replicatable;
527         }
528
529         switch(op) {
530                 /*
531                  * For attach(), we cannot simply redirect to the gate
532                  * agent, because we need to modify the thread that is
533                  * attached to the IRQ
534                  */
535                 case L4_IRQ_SENDER_OP_ATTACH:
536                         {
537                                 l4_umword_t attach_cap      = l4_utcb_mr_u(utcb)->mr[3] & L4_FPAGE_ADDR_MASK;
538                                 DEBUG() << "attach " << std::hex << (attach_cap >> L4_CAP_SHIFT);
539                                 Romain::Thread_group *group = theObjectFactory.thread_for_cap(attach_cap >> L4_CAP_SHIFT);
540                                 l4_msgtag_t ret;
541
542                                 if (!group) {
543                                         ERROR() << "Unimplemented: Attaching someone else but myself!\n";
544                                         enter_kdebug();
545                                 }
546
547                                 ret = irq->attach(label, group->gateagent->listener_cap);
548
549                                 t->vcpu()->r()->ax = ret.raw;
550                                 DEBUG() << std::hex << ret.raw ;
551                                 return Romain::Observer::Replicatable;
552                         }
553                         break;
554         }
555
556         return Romain::Observer::Replicatable;
557 }