4 * Implementation of Romain syscall handling.
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.
14 #include "../app_loading"
15 #include "../locking.h"
17 #include "../thread_group.h"
19 #include "observers.h"
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>
27 #define MSG() DEBUGf(Romain::Log::Faults)
28 #define MSGt(t) DEBUGf(Romain::Log::Faults) << "[" << t->vcpu() << "] "
29 #define DEBUGt(t) DEBUG() << "[" << t->vcpu() << "] "
31 #include "syscalls_factory.h" // uses MSG() defined above (ugly)
33 DEFINE_EMPTY_STARTUP(SyscallObserver)
35 static l4_umword_t num_syscalls;
38 void Romain::SyscallObserver::status() const
40 INFO() << "[sys ] System call count: " << num_syscalls;
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;
51 Romain::Factory theObjectFactory;
53 Romain::Observer::ObserverReturnVal
54 Romain::SyscallObserver::notify(Romain::App_instance *i,
55 Romain::App_thread *t,
56 Romain::Thread_group *tg,
59 enum { Syscall_magic_address = 0xEACFF003, };
60 Romain::Observer::ObserverReturnVal retval = Romain::Observer::Ignored;
62 if (t->vcpu()->r()->trapno != 13) {
66 /* SYSENTER / INT30 */
67 if (t->vcpu()->r()->ip == Syscall_magic_address) {
69 unsigned long long t1, t2;
74 l4_msgtag_t *tag = reinterpret_cast<l4_msgtag_t*>(&t->vcpu()->r()->ax);
75 MSG() << "SYSENTER(" << tg->name << ") tag = " << std::hex << tag->label();
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();
88 * EBX is return address
90 * -> we need to remember these
92 l4_addr_t ebx_pre = t->vcpu()->r()->bx;
93 l4_addr_t ebp_pre = t->vcpu()->r()->bp;
95 switch(tag->label()) {
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>.
104 if ((t->vcpu()->r()->dx & L4_INVALID_CAP) == L4_INVALID_CAP) {
105 tg->gateagent->trigger_agent(t);
107 nullhandler.proxy_syscall(i, t, tg, a);
109 retval = Romain::Observer::Replicatable;
112 case L4_PROTO_FACTORY:
113 retval = theObjectFactory.handle(i, t, tg, a);
117 retval = irq.handle(i, t, tg, a);
120 case L4_PROTO_IRQ_SENDER:
121 retval = irq_sender.handle(i, t, tg, a);
124 case L4_PROTO_THREAD:
126 * Each instance needs to perform its own
129 retval = threadsyscall.handle(i, t, tg, a);
133 if ((t->vcpu()->r()->dx & ~0xF) == L4RE_THIS_TASK_CAP) {
134 retval = handle_task(i, t, a);
136 nullhandler.proxy_syscall(i, t, tg, a);
137 retval = Romain::Observer::Replicatable;
141 case L4Re::Rm::Protocol:
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.
148 retval = rm.handle(i, t, tg, a);
151 case L4Re::Parent::Protocol:
153 * The parent protocol is only used for exitting.
157 gettimeofday(&tv, 0);
158 INFO() << "Instance " << i->id() << " exitting. Time "
159 << YELLOW << tv.tv_sec << "." << tv.tv_usec
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;
169 Romain::_the_instance_manager->show_stats();
171 if (REBOOT_ON_EXIT) enter_kdebug("*#^");
174 nullhandler.proxy_syscall(i, t, tg, a);
175 retval = Romain::Observer::Replicatable;
179 case L4_PROTO_SCHEDULER:
180 retval = sched.handle(i, t, tg, a);
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.
190 nullhandler.proxy_syscall(i, t, tg, a);
191 retval = Romain::Observer::Replicatable;
196 t->vcpu()->r()->ip = ebx_pre;
197 t->vcpu()->r()->sp = ebp_pre;
201 t->count_syscalls(t2-t1);
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;
219 t->vcpu()->print_state();
220 INFO() << "err = " << std::hex << t->vcpu()->r()->err;
221 enter_kdebug("GPF in replica");
228 void Romain::SyscallHandler::proxy_syscall(Romain::App_instance *,
229 Romain::App_thread* t,
230 Romain::Thread_group* tg,
233 char backup_utcb[L4_UTCB_OFFSET]; // for storing local UTCB content
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??");
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.
244 store_utcb((char*)cur_utcb, backup_utcb);
245 store_utcb((char*)addr, (char*)cur_utcb);
247 //t->print_vcpu_state();
248 //Romain::dump_mem((l4_umword_t*)addr, 40);
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)
270 store_utcb((char*)cur_utcb, (char*)addr);
271 store_utcb(backup_utcb, (char*)cur_utcb);
273 //t->print_vcpu_state();
274 //Romain::dump_mem((l4_umword_t*)addr, 40);
275 //enter_kdebug("done syscall");
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)
285 MSGt(t) << "RM PROTOCOL";
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??");
291 //t->print_vcpu_state();
292 //Romain::dump_mem((l4_umword_t*)utcb, 40, 4);
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;
301 //t->print_vcpu_state();
302 //Romain::dump_mem((l4_umword_t*)utcb, 40);
304 return Romain::Observer::Replicatable;
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)
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??");
319 //t->print_vcpu_state();
320 //Romain::dump_mem((l4_umword_t*)utcb, 40);
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;
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) {
330 group = theObjectFactory.thread_for_cap(dest >> L4_CAP_SHIFT);
332 DEBUG() << "tgroup " << group;
335 case L4_THREAD_CONTROL_OP:
336 group->control(t, utcb, am);
337 return Romain::Observer::Replicatable;
338 case L4_THREAD_EX_REGS_OP:
341 case L4_THREAD_SWITCH_OP:
342 enter_kdebug("THREAD: switch");
344 case L4_THREAD_STATS_OP:
345 enter_kdebug("THREAD: stats");
347 case L4_THREAD_VCPU_RESUME_OP:
348 enter_kdebug("THREAD: vcpu_resume");
350 case L4_THREAD_REGISTER_DELETE_IRQ_OP:
351 enter_kdebug("THREAD: irq");
353 case L4_THREAD_MODIFY_SENDER_OP:
354 enter_kdebug("THREAD: modify sender");
356 case L4_THREAD_VCPU_CONTROL_OP:
357 enter_kdebug("THREAD: vcpu control");
359 case L4_THREAD_VCPU_CONTROL_EXT_OP:
360 enter_kdebug("THREAD: vcpu control ext");
362 case L4_THREAD_X86_GDT_OP:
366 ERROR() << "unknown thread op: " << std::hex << op << "\n";
370 return Romain::Observer::Replicatable;
371 //enter_kdebug("thread");
375 Romain::Observer::ObserverReturnVal
376 Romain::SyscallObserver::handle_task(Romain::App_instance* i,
377 Romain::App_thread* t,
378 Romain::App_model* a)
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;
385 case L4_TASK_UNMAP_OP:
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);
393 //t->vcpu()->r()->ax = 0;
395 case L4_TASK_CAP_INFO_OP:
396 nullhandler.proxy_syscall(i,t,0,a);
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?");
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)
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??");
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
429 case L4_PROTO_THREAD:
430 create_thread(inst, t, tg, am, cap);
431 return Romain::Observer::Replicatable;
434 create_irq(inst, t, tg, am, cap);
435 return Romain::Observer::Replicatable;
437 case L4Re::Dataspace::Protocol:
439 SyscallHandler::proxy_syscall(inst, t, tg, am);
440 return Romain::Observer::Replicatable;
447 enter_kdebug("theObjectFactory");
448 return Romain::Observer::Finished;
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)
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];
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);
467 //enter_kdebug("run_thread != 1");
468 SyscallHandler::proxy_syscall(inst, t, tg, am);
471 return Romain::Observer::Replicatable;
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)
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;
486 L4::Cap<L4::Irq> irq(cap);
488 DEBUGt(t) << "IRQ: cap = " << std::hex << cap << " op = " << op;
490 if (!theObjectFactory.is_irq(cap)) {
491 SyscallHandler::proxy_syscall(inst, t, tg, am);
492 return Romain::Observer::Replicatable;
496 case L4_IRQ_OP_TRIGGER:
497 DEBUGt(t) << ":: trigger";
498 //enter_kdebug("trigger");
502 DEBUGt(t) << ":: eoi";
503 tg->gateagent->trigger_agent(t);
507 return Romain::Observer::Replicatable;
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)
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;
520 L4::Cap<L4::Irq> irq(cap);
522 DEBUGt(t) << "IRQ: cap = " << std::hex << cap << " op = " << op;
524 if (!theObjectFactory.is_irq(cap)) {
525 SyscallHandler::proxy_syscall(inst, t, tg, am);
526 return Romain::Observer::Replicatable;
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
535 case L4_IRQ_SENDER_OP_ATTACH:
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);
543 ERROR() << "Unimplemented: Attaching someone else but myself!\n";
547 ret = irq->attach(label, group->gateagent->listener_cap);
549 t->vcpu()->r()->ax = ret.raw;
550 DEBUG() << std::hex << ret.raw ;
551 return Romain::Observer::Replicatable;
556 return Romain::Observer::Replicatable;