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/util/region_mapping_svr>
22 #include <l4/sys/segment.h>
23 #include <l4/sys/consts.h>
25 #define MSG() DEBUGf(Romain::Log::Faults)
26 #define MSGt(t) DEBUGf(Romain::Log::Faults) << "[" << t->vcpu() << "] "
27 #define DEBUGt(t) DEBUG() << "[" << t->vcpu() << "] "
29 #include "syscalls_factory.h" // uses MSG() defined above (ugly)
31 DEFINE_EMPTY_STARTUP(SyscallObserver)
33 static unsigned long num_syscalls;
36 void Romain::SyscallObserver::status() const
38 INFO() << "[sys ] System call count: " << num_syscalls;
42 static Romain::ThreadHandler threadsyscall;
43 static Romain::SyscallHandler nullhandler;
44 static Romain::RegionManagingHandler rm;
45 static Romain::Scheduling sched;
46 static Romain::IrqHandler irq;
48 Romain::Factory theObjectFactory;
50 Romain::Observer::ObserverReturnVal
51 Romain::SyscallObserver::notify(Romain::App_instance *i,
52 Romain::App_thread *t,
53 Romain::Thread_group *tg,
56 enum { Syscall_magic_address = 0xEACFF003, };
57 Romain::Observer::ObserverReturnVal retval = Romain::Observer::Ignored;
59 if (t->vcpu()->r()->trapno != 13) {
63 /* SYSENTER / INT30 */
64 if (t->vcpu()->r()->ip == Syscall_magic_address) {
67 l4_msgtag_t *tag = reinterpret_cast<l4_msgtag_t*>(&t->vcpu()->r()->ax);
68 MSG() << "SYSENTER(" << tg->name << ") tag = " << std::hex << tag->label();
70 Measurements::GenericEvent* ev = Romain::_the_instance_manager->logbuf()->next();
71 ev->header.tsc = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
72 ev->header.vcpu = (l4_uint32_t)t->vcpu();
73 ev->header.type = Measurements::Syscall;
74 ev->data.sys.eip = t->vcpu()->r()->bx;
75 ev->data.sys.label = tag->label();
79 * EBX is return address
81 * -> we need to remember these
83 l4_addr_t ebx_pre = t->vcpu()->r()->bx;
84 l4_addr_t ebp_pre = t->vcpu()->r()->bp;
86 switch(tag->label()) {
90 * Catch the open_wait versions of IPC as they require
91 * redirection through the gateagent thread. Open wait
92 * is defined by the IPC bindings as one where EDX is set
93 * to L4_INVALID_CAP | <some_flags>.
95 if ((t->vcpu()->r()->dx & L4_INVALID_CAP) == L4_INVALID_CAP) {
96 tg->gateagent->trigger_agent(t);
98 nullhandler.proxy_syscall(i, t, tg, a);
100 retval = Romain::Observer::Replicatable;
103 case L4_PROTO_FACTORY:
104 retval = theObjectFactory.handle(i, t, tg, a);
108 retval = irq.handle(i, t, tg, a);
111 case L4_PROTO_THREAD:
113 * Each instance needs to perform its own
116 retval = threadsyscall.handle(i, t, tg, a);
120 if ((t->vcpu()->r()->dx & ~0xF) == L4RE_THIS_TASK_CAP) {
121 handle_task(i, t, a);
122 retval = Romain::Observer::Finished;
124 nullhandler.proxy_syscall(i, t, tg, a);
125 retval = Romain::Observer::Replicatable;
129 case L4Re::Protocol::Rm:
131 * Region management is done only once as e.g.,
132 * regions for attaching need to be replicated
133 * across instances. The real adaptation then
134 * happens during page fault handling.
136 retval = rm.handle(i, t, tg, a);
139 case L4Re::Protocol::Parent:
141 * The parent protocol is only used for exitting.
145 gettimeofday(&tv, 0);
146 INFO() << "Instance " << i->id() << " exitting. Time "
147 << YELLOW << tv.tv_sec << "." << tv.tv_usec
150 Measurements::GenericEvent* ev = Romain::_the_instance_manager->logbuf()->next();
151 ev->header.tsc = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
152 ev->header.vcpu = (l4_uint32_t)t->vcpu();
153 ev->header.type = Measurements::Thread_stop;
155 Romain::_the_instance_manager->show_stats();
157 if (1) enter_kdebug("*#^");
159 nullhandler.proxy_syscall(i, t, tg, a);
160 retval = Romain::Observer::Replicatable;
164 case L4_PROTO_SCHEDULER:
165 retval = sched.handle(i, t, tg, a);
170 * Proxied syscalls are always only executed
171 * once because for the outside world it must
172 * look as if the master server _is_ the one
173 * application everyone is talking to.
175 nullhandler.proxy_syscall(i, t, tg, a);
176 retval = Romain::Observer::Replicatable;
181 t->vcpu()->r()->ip = ebx_pre;
182 t->vcpu()->r()->sp = ebp_pre;
184 } else if (t->vcpu()->r()->err == 0x152) { // INT $42
185 INFO() << "[" << std::hex << (unsigned)t->vcpu() << "] INT 42 ("
186 << t->vcpu()->r()->ip << ")";
187 t->vcpu()->r()->ip += 2;
188 retval = Romain::Observer::Replicatable;
190 t->vcpu()->print_state();
191 INFO() << "err = " << std::hex << t->vcpu()->r()->err;
193 enter_kdebug("GPF in replica");
200 void Romain::SyscallHandler::proxy_syscall(Romain::App_instance *,
201 Romain::App_thread* t,
202 Romain::Thread_group* tg,
205 char backup_utcb[L4_UTCB_OFFSET]; // for storing local UTCB content
207 l4_utcb_t *addr = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
208 l4_utcb_t *cur_utcb = l4_utcb();
209 MSGt(t) << "UTCB @ " << std::hex << (unsigned)addr;
210 _check((l4_addr_t)addr == ~0UL, "remote utcb ptr??");
213 * We are going to perform the system call on behalf of the client. This will
214 * thrash our local UTCB, so we want to store it here.
216 store_utcb((char*)cur_utcb, backup_utcb);
217 store_utcb((char*)addr, (char*)cur_utcb);
219 //t->print_vcpu_state();
220 //Romain::dump_mem((unsigned*)addr, 40);
222 /* Perform Fiasco system call */
223 asm volatile (L4_ENTER_KERNEL
224 : "=a" (t->vcpu()->r()->ax),
225 "=b" (t->vcpu()->r()->bx),
226 /* ECX, EDX are overwritten anyway */
227 "=S" (t->vcpu()->r()->si),
228 "=D" (t->vcpu()->r()->di)
229 : "a" (t->vcpu()->r()->ax),
230 /* EBX and EBP will be overwritten with local
231 * values in L4_ENTER_KERNEL */
232 "c" (t->vcpu()->r()->cx),
233 "d" (t->vcpu()->r()->dx),
234 "S" (t->vcpu()->r()->si),
235 "D" (t->vcpu()->r()->di)
242 store_utcb((char*)cur_utcb, (char*)addr);
243 store_utcb(backup_utcb, (char*)cur_utcb);
245 //t->print_vcpu_state();
246 //Romain::dump_mem((unsigned*)addr, 40);
247 //enter_kdebug("done syscall");
251 Romain::Observer::ObserverReturnVal
252 Romain::RegionManagingHandler::handle(Romain::App_instance* i,
253 Romain::App_thread* t,
254 Romain::Thread_group* tg,
255 Romain::App_model * a)
257 MSGt(t) << "RM PROTOCOL";
259 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
260 MSGt(t) << "UTCB @ " << std::hex << (unsigned)utcb;
261 _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
263 //t->print_vcpu_state();
264 //Romain::dump_mem((unsigned*)utcb, 40);
267 Romain::Rm_guard r(a->rm(), i->id());
268 L4::Ipc::Iostream ios(utcb);
269 L4Re::Util::region_map_server<Romain::Region_map_server>(a->rm(), ios);
270 t->vcpu()->r()->ax = 0;
273 //t->print_vcpu_state();
274 //Romain::dump_mem((unsigned*)utcb, 40);
276 return Romain::Observer::Replicatable;
280 Romain::Observer::ObserverReturnVal
281 Romain::ThreadHandler::handle(Romain::App_instance *,
282 Romain::App_thread* t,
283 Romain::Thread_group * tg,
284 Romain::App_model *am)
286 MSGt(t) << "Thread system call";
287 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
288 MSGt(t) << "UTCB @ " << std::hex << (unsigned)utcb;
289 _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
291 //t->print_vcpu_state();
292 //Romain::dump_mem((unsigned*)utcb, 40);
294 l4_umword_t op = l4_utcb_mr_u(utcb)->mr[0] & L4_THREAD_OPCODE_MASK;
295 l4_umword_t dest = t->vcpu()->r()->dx & L4_CAP_MASK;
297 DEBUG() << "dest cap " << std::hex << dest << " " << L4_INVALID_CAP;
298 Romain::Thread_group* group = (Romain::Thread_group*)0xdeadbeef;
299 if (dest == L4_INVALID_CAP) {
302 group = theObjectFactory.thread_for_cap(dest >> L4_CAP_SHIFT);
304 DEBUG() << "tgroup " << group;
307 case L4_THREAD_CONTROL_OP:
308 group->control(t, utcb, am);
309 return Romain::Observer::Replicatable;
310 case L4_THREAD_EX_REGS_OP:
313 case L4_THREAD_SWITCH_OP:
314 enter_kdebug("THREAD: switch");
316 case L4_THREAD_STATS_OP:
317 enter_kdebug("THREAD: stats");
319 case L4_THREAD_VCPU_RESUME_OP:
320 enter_kdebug("THREAD: vcpu_resume");
322 case L4_THREAD_REGISTER_DELETE_IRQ_OP:
323 enter_kdebug("THREAD: irq");
325 case L4_THREAD_MODIFY_SENDER_OP:
326 enter_kdebug("THREAD: modify sender");
328 case L4_THREAD_VCPU_CONTROL_OP:
329 enter_kdebug("THREAD: vcpu control");
331 case L4_THREAD_VCPU_CONTROL_EXT_OP:
332 enter_kdebug("THREAD: vcpu control ext");
334 case L4_THREAD_GDT_X86_OP:
337 case L4_THREAD_SET_FS_AMD64_OP:
338 enter_kdebug("THREAD: set fs amd64");
341 ERROR() << "unknown thread op: " << std::hex << op;
345 return Romain::Observer::Replicatable;
346 //enter_kdebug("thread");
350 void Romain::SyscallObserver::handle_task(Romain::App_instance* i,
351 Romain::App_thread* t,
352 Romain::App_model* a)
354 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
355 l4_umword_t op = l4_utcb_mr_u(utcb)->mr[0] & L4_THREAD_OPCODE_MASK;
357 case L4_TASK_UNMAP_OP:
360 i->unmap(l4_utcb_mr_u(utcb)->mr[2]);
363 case L4_TASK_CAP_INFO_OP:
364 nullhandler.proxy_syscall(i,t,0,a);
367 MSGt(t) << "Task system call";
368 MSGt(t) << "UTCB @ " << std::hex << (unsigned)utcb << " op: " << op
369 << " cap " << (t->vcpu()->r()->dx & ~0xF) << " " << L4RE_THIS_TASK_CAP;
370 t->print_vcpu_state();
371 enter_kdebug("unknown task op?");
377 Romain::Observer::ObserverReturnVal
378 Romain::Factory::handle(Romain::App_instance* inst,
379 Romain::App_thread* t,
380 Romain::Thread_group* tg,
381 Romain::App_model* am)
383 MSGt(t) << "Factory system call";
384 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
385 MSGt(t) << "UTCB @ " << std::hex << (unsigned)utcb;
386 _check((l4_addr_t)utcb == ~0UL, "remote utcb ptr??");
388 l4_umword_t obj = l4_utcb_mr_u(utcb)->mr[0];
389 l4_umword_t cap = l4_utcb_br_u(utcb)->br[0] & ~L4_RCV_ITEM_SINGLE_CAP;
390 MSGt(t) << std::hex << L4_PROTO_THREAD;
391 MSGt(t) << "object type: " << std::hex << obj
395 case L4_PROTO_THREAD:
396 create_thread(inst, t, tg, am, cap);
397 return Romain::Observer::Replicatable;
400 create_irq(inst, t, tg, am, cap);
401 return Romain::Observer::Replicatable;
403 case L4Re::Protocol::Dataspace:
404 SyscallHandler::proxy_syscall(inst, t, tg, am);
405 return Romain::Observer::Replicatable;
411 enter_kdebug("theObjectFactory");
412 return Romain::Observer::Finished;
416 Romain::Observer::ObserverReturnVal
417 Romain::Scheduling::handle(Romain::App_instance* inst,
418 Romain::App_thread* t,
419 Romain::Thread_group* tg,
420 Romain::App_model* am)
422 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
423 l4_umword_t op = l4_utcb_mr_u(utcb)->mr[0];
425 MSGt(t) << "\033[32mschedule(" << std::hex << op << ")\033[0m";
426 if (op == L4_SCHEDULER_RUN_THREAD_OP) {
427 l4_umword_t cap = l4_utcb_mr_u(utcb)->mr[6] >> L4_CAP_SHIFT;
428 Romain::Thread_group* group = theObjectFactory.thread_for_cap(cap);
429 group->scheduler_run(t);
431 //enter_kdebug("run_thread != 1");
432 SyscallHandler::proxy_syscall(inst, t, tg, am);
435 return Romain::Observer::Replicatable;
439 Romain::Observer::ObserverReturnVal
440 Romain::IrqHandler::handle(Romain::App_instance* inst,
441 Romain::App_thread* t,
442 Romain::Thread_group* tg,
443 Romain::App_model* am)
445 l4_utcb_t *utcb = reinterpret_cast<l4_utcb_t*>(t->remote_utcb());
446 unsigned op = l4_utcb_mr_u(utcb)->mr[0];
447 unsigned label = l4_utcb_mr_u(utcb)->mr[1];
448 unsigned cap = t->vcpu()->r()->dx & L4_CAP_MASK;
450 L4::Cap<L4::Irq> irq(cap);
452 DEBUGt(t) << "IRQ: cap = " << std::hex << cap << " op = " << op;
454 if (!theObjectFactory.is_irq(cap)) {
455 SyscallHandler::proxy_syscall(inst, t, tg, am);
456 return Romain::Observer::Replicatable;
461 * For attach(), we cannot simply redirect to the gate
462 * agent, because we need to modify the thread that is
463 * attached to the IRQ
465 case L4_IRQ_OP_ATTACH:
467 l4_umword_t attach_cap = l4_utcb_mr_u(utcb)->mr[3] & L4_FPAGE_ADDR_MASK;
468 DEBUG() << "attach " << std::hex << (attach_cap >> L4_CAP_SHIFT);
469 Romain::Thread_group *group = theObjectFactory.thread_for_cap(attach_cap >> L4_CAP_SHIFT);
473 ERROR() << "Unimplemented: Attaching someone else but myself!";
477 ret = irq->attach(label, group->gateagent->listener_cap);
479 t->vcpu()->r()->ax = ret.raw;
480 DEBUG() << std::hex << ret.raw ;
481 return Romain::Observer::Replicatable;
485 case L4_IRQ_OP_TRIGGER:
486 DEBUGt(t) << ":: trigger";
487 //enter_kdebug("trigger");
491 DEBUGt(t) << ":: eoi";
492 tg->gateagent->trigger_agent(t);
495 case L4_IRQ_OP_CHAIN:
496 enter_kdebug("irq::chain?");
499 return Romain::Observer::Replicatable;