4 * Here's where the real stuff is going on
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.
17 #include "app_loading"
18 #include "fault_handlers/syscalls_handler.h"
22 #include <l4/sys/kdebug.h>
23 #include <l4/util/bitops.h>
24 #include <l4/util/rdtsc.h>
26 #include <pthread-l4.h>
27 #include <l4/sys/segment.h>
29 #define MSG() DEBUGf(Romain::Log::Faults)
30 #define MSGi(inst) MSG() << "[" << (inst)->id() << "] "
31 #define MSGit(inst,tg) MSG() << "[" << (inst)->id() << "] \033[34;1m{" << tg->name << "}\033[0m "
33 #define ____dummy " /* ST2 highlighting fix XXX */
35 EXTERN_C void *pthread_fn(void *data);
36 EXTERN_C void *pthread_fn(void *data)
38 Romain::App_thread *t = (Romain::App_thread*)data;
40 l4_cap_idx_t cap = (l4_cap_idx_t)pthread_getl4cap(pthread_self());
41 t->vcpu_cap(L4::Cap<L4::Thread>(cap));
43 DEBUG() << "vcpu @ " << (void*)t->vcpu();
44 DEBUG() << "thread entry: " << (void*)t->thread_entry();
47 * Thread creation, copied from the example again.
49 L4::Thread::Attr attr;
50 attr.pager(L4::cap_reinterpret_cast<L4::Thread>(L4Re::Env::env()->rm()));
51 attr.exc_handler(L4Re::Env::env()->main_thread());
52 // attr.bind(t->vcpu_utcb(), L4Re::This_task);
54 chksys(t->vcpu_cap()->control(attr), "control");
55 chksys(t->vcpu_cap()->vcpu_control((l4_addr_t)t->vcpu()), "enable VCPU");
57 l4_sched_param_t sp = l4_sched_param(2);
58 sp.affinity = l4_sched_cpu_set(t->cpu(), 0);
59 chksys(L4Re::Env::env()->scheduler()->run_thread(t->vcpu_cap(),
63 MSG() << "!" << std::hex << (void*)t->thread_sp();
64 MSG() << "?" << std::hex << (void*)t->handler_sp();
66 asm volatile("mov %0, %%esp\n\t"
69 : "r" (t->handler_sp()),
70 "r" (t->thread_entry())
73 enter_kdebug("blub?");
81 Romain::InstanceManager *m;
82 Romain::App_instance *i;
83 Romain::App_thread *t;
84 Romain::Thread_group *tg;
89 : m(0), i(0), t(0), tg(0), a(0), cap(L4_INVALID_CAP)
98 l4_cap_idx_t _split_handler;
99 Romain::InstanceManager *_im;
100 Romain::Replicator _replicator;
102 unsigned long * _checksums;
104 void wait_for_instances()
106 for (unsigned cnt = 0; cnt < _im->instance_count(); ++cnt) {
108 l4_umword_t label = 0;
109 l4_msgtag_t t = l4_ipc_wait(l4_utcb(), &label, L4_IPC_NEVER);
110 //MSG() << "Split handler notified: " << std::hex << t.label();
111 _psi[cnt] = (SplitInfo*)l4_utcb_mr()->mr[0];
113 MSG() << (void*)&_psi[cnt] << " " << _psi[cnt];
115 while (_psi[cnt] == 0) {
116 //MSG() << (void*)_psi[cnt];
120 MSG() << (void*)&_psi[cnt] << " " << _psi[cnt] << " Split handler notified";
122 _checksums[cnt] = _psi[cnt]->t->csum_state();
128 bool validate_instances()
130 for (unsigned cnt = 1; cnt < _im->instance_count(); ++cnt) {
131 if (_checksums[cnt] != _checksums[cnt-1]) {
132 ERROR() << std::hex << _checksums[cnt] << " != " << _checksums[cnt-1];
133 ERROR() << "State mismatch detected!";
134 ERROR() << "=== vCPU states ===";
136 for (unsigned i = 0; i < _im->instance_count(); ++i) {
137 ERROR() << "Instance " << _psi[i]->i->id() << " "
138 << "csum " << std::hex << _psi[i]->t->csum_state();
139 _psi[i]->t->print_vcpu_state();
150 L4vcpu::Vcpu *vcpu = _psi[0]->t->vcpu();
151 unsigned trap = _psi[0]->t->vcpu()->r()->trapno;
154 MSGi(_psi[0]->i) << "\033[33;1mTRAP 0x"
155 << std::hex << vcpu->r()->trapno
156 << " @ 0x" << vcpu->r()->ip << "\033[0m";
158 Romain::Observer::ObserverReturnVal v
159 = _im->fault_notify(_psi[0]->i, _psi[0]->t, _psi[0]->tg, _psi[0]->a);
162 case Romain::Observer::Finished:
164 for (unsigned c = 1; c < _im->instance_count(); ++c) {
165 _im->fault_notify(_psi[c]->i, _psi[c]->t, _psi[c]->tg, _psi[c]->a);
169 case Romain::Observer::Replicatable:
171 _replicator.put(_psi[0]->t);
172 for (unsigned c = 1; c < _im->instance_count(); ++c) {
173 _replicator.get(_psi[c]->t);
178 enter_kdebug("notify?");
182 if ((trap = _psi[0]->t->get_pending_trap()) != 0)
183 _psi[0]->t->vcpu()->r()->trapno = trap;
188 void resume_instances()
190 for (unsigned c = 0; c < _im->instance_count(); ++c) {
191 MSGi(_psi[c]->i) << "Resuming instance @ " << std::hex << _psi[c]->t->vcpu()->r()->ip;
193 l4_ipc_send(_psi[c]->cap, l4_utcb(), l4_msgtag(0,0,0,0), L4_IPC_NEVER);
198 MSG() << "... resumed.";
203 static SplitHandler* _handlers[5];
205 static SplitHandler* get(unsigned idx)
207 assert(idx == 0); // for now
208 return _handlers[idx];
211 void notify(Romain::App_instance* i,
212 Romain::App_thread* t,
213 Romain::Thread_group* tg,
214 Romain::App_model* a)
219 //MSGi(i) << "split handler is " << std::hex << SplitHandler::split_handler_cap();
226 si.cap = t->vcpu_cap().cap();
228 l4_utcb_mr()->mr[0] = (l4_umword_t)&si;
229 l4_msgtag_t tag = l4_msgtag(0xF00, 1, 0, 0);
230 l4_msgtag_t res = l4_ipc_call(SplitHandler::split_handler_cap(),
231 l4_utcb(), tag, L4_IPC_NEVER);
239 MSG() << (void*)&_psi[i->id()] << " " << (void*)&si;
241 while (_psi[i->id()] != 0) {
245 MSGi(i) << "handled.";
248 SplitHandler(Romain::InstanceManager* im)
249 : _split_handler(pthread_getl4cap(pthread_self())),
250 _im(im), _replicator()
252 _psi = new SplitInfo*[_im->instance_count()];
253 _checksums = new unsigned long [_im->instance_count()];
254 memset(_psi, 0, sizeof(SplitInfo*) * _im->instance_count());
261 delete [] _checksums;
267 MSG() << "Instance mgr: " << (void*)_im;
268 MSG() << "Instances: " << _im->instance_count();
271 wait_for_instances();
273 DEBUG() << "received faults from " << _im->instance_count()
276 if (!validate_instances())
277 enter_kdebug("recover");
285 void psi(unsigned idx, SplitInfo* si)
288 l4_cap_idx_t split_handler_cap()
289 { return _split_handler; }
293 SplitHandler* SplitHandler::_handlers[5] = {0};
296 EXTERN_C void *split_handler_fn(void* data)
298 //SplitHandler::split_handler_cap(pthread_getl4cap(pthread_self()));
300 SplitHandler::_handlers[0] = new SplitHandler(reinterpret_cast<Romain::InstanceManager*>(data));
301 SplitHandler::get(0)->run();
303 enter_kdebug("split_handler terminated!");
307 #endif // SPLIT_HANDLING
309 void __attribute__((noreturn)) Romain::InstanceManager::VCPU_startup(Romain::InstanceManager *m,
310 Romain::App_instance *i,
311 Romain::App_thread *t,
312 Romain::Thread_group *tg,
313 Romain::App_model*am)
315 L4vcpu::Vcpu *vcpu = t->vcpu();
316 vcpu->task(i->vcpu_task());
320 t->commit_client_gdt();
321 //t->print_vcpu_state();
324 snprintf(namebuf, 16, "%s.%d", tg->name.c_str(), i->id());
325 l4_debugger_set_object_name(t->vcpu_cap().cap(), namebuf);
326 DEBUG() << std::hex << (unsigned)t->vcpu_cap().cap() << " = "
327 << l4_debugger_global_id(t->vcpu_cap().cap())
331 gettimeofday(&tv, 0);
332 if (Romain::Log::withtime)
333 INFO() << "\033[33;1mStarting @ " << tv.tv_sec << "." << tv.tv_usec << "\033[0m";
335 INFO() << "\033[33;1mStarting\033[0m";
337 MSGit(i,tg) << "Resuming instance @ " << (void*)vcpu->r()->ip << " ...";
339 Measurements::GenericEvent* ev = m->logbuf()->next();
340 ev->header.tsc = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
341 ev->header.vcpu = (l4_uint32_t)vcpu;
342 ev->header.type = Measurements::Thread_start;
344 L4::Cap<L4::Thread> cap = t->vcpu_cap();
346 cap->vcpu_resume_commit(cap->vcpu_resume_start());
348 enter_kdebug("after resume");
353 static void local_vCPU_handling(Romain::InstanceManager *m,
354 Romain::App_instance *i,
355 Romain::App_thread *t,
356 Romain::Thread_group *tg,
357 Romain::App_model *a)
359 // XXX: At this point we might want to reset the GDT to the view that is
360 // expected by the master task, which might differ from the client.
362 L4vcpu::Vcpu *vcpu = t->vcpu();
363 unsigned trap = t->vcpu()->r()->trapno;
366 * We potentially handle multiple traps here: As we are emulating a bunch
367 * of instructions (e.g., write PF emulation), some real instructions are never
368 * actually executed and may thus not raise certain exceptions such as the INT1 single
369 * step exception. Observers emulating behavior need to be aware of that and inject
370 * a new exception in such circumstances.
373 MSGit(i,tg) << "\033[33;1mTRAP 0x" << std::hex << vcpu->r()->trapno
374 << " @ 0x" << vcpu->r()->ip << "\033[0m";
376 if (t->vcpu()->r()->ip == 0xA041) {
377 m->fault_notify(i,t,tg,a);
383 * HACK: In case we are using lock-internal determinism, there's a special
384 * entry address in which a single replica will signal us if we need
385 * to wake up another thread waiting for a replica. If we encounter
386 * this address, we skip redundancy handling and directly notify the
389 if (vcpu->r()->ip == 0xA041) {
390 // shortcut for unlock()
391 m->fault_notify(i,t,tg,a);
396 Romain::Observer::ObserverReturnVal v = Romain::Observer::Invalid;
399 * Enter redundancy mode. May cause vCPU to block until leader vCPU executed
402 Romain::RedundancyCallback::EnterReturnVal rv = tg->redundancyCB->enter(i,t,a);
403 //MSGi(i) << "red::enter: " << rv;
406 * Case 1: we are the first to exec this system call.
408 if (rv == Romain::RedundancyCallback::First_syscall) {
409 v = m->fault_notify(i,t,tg,a);
410 MSGit(i,tg) << "fault_notify: " << v;
412 case Romain::Observer::Finished:
413 case Romain::Observer::Finished_wait:
414 case Romain::Observer::Finished_step:
415 case Romain::Observer::Finished_wakeup:
416 //MSGi(i) << "leader_repeat()";
417 tg->redundancyCB->leader_repeat(i,t,a);
419 case Romain::Observer::Replicatable:
420 tg->redundancyCB->leader_replicate(i,t,a);
423 //enter_kdebug("fault was not finished/replicatable");
428 * Case 2: leader told us to do the syscall ourselves
430 else if (rv == Romain::RedundancyCallback::Repeat_syscall) {
431 v = m->fault_notify(i,t,tg,a);
432 MSGit(i,tg) << "fault_notify: " << v;
436 * Special handling for the Finished_{wakeup,wait,step} cases
437 * used by the fault injector.
440 case Romain::Observer::Finished_wait:
441 // go to sleep until woken up
442 tg->redundancyCB->wait(i,t,a);
444 case Romain::Observer::Finished_wakeup:
445 // wakeup -> first needs to ensure that all other
446 // vCPUs are actually waiting
447 tg->redundancyCB->silence(i,t,a);
448 tg->redundancyCB->wakeup(i,t,a);
450 case Romain::Observer::Finished_step:
451 // let other vCPUs step until they go to sleep
452 tg->redundancyCB->silence(i,t,a);
458 if ((trap = t->get_pending_trap()) != 0)
459 t->vcpu()->r()->trapno = trap;
461 tg->redundancyCB->resume(i, t, a);
464 //print_vcpu_state();
465 MSGit(i, tg) << "Resuming instance @ " << std::hex << t->vcpu()->r()->ip;
466 //t->print_vcpu_state();
471 static void split_vCPU_handling(Romain::InstanceManager *m,
472 Romain::App_instance *i,
473 Romain::App_thread *t,
474 Romain::Thread_group *tg,
475 Romain::App_model *a)
478 SplitHandler::get(0)->notify(i,t,a);
480 #endif // SPLIT_HANDLING
484 static void migrated_vCPU_handling(Romain::InstanceManager *m,
485 Romain::App_instance *i,
486 Romain::App_thread *t,
487 Romain::Thread_group *tg,
488 Romain::App_model *a)
490 l4_sched_param_t sp = l4_sched_param(2);
491 sp.affinity = l4_sched_cpu_set(0, 0);
492 chksys(L4Re::Env::env()->scheduler()->run_thread(t->vcpu_cap(),
495 local_vCPU_handling(m, i, t, a);
497 sp = l4_sched_param(2);
498 sp.affinity = l4_sched_cpu_set(t->cpu(), 0);
499 chksys(L4Re::Env::env()->scheduler()->run_thread(t->vcpu_cap(),
502 #endif // MIGRATE_VCPU
505 * VCPU fault entry point.
507 * Calls the registered observers and keeps track of any further faults that might get
508 * injected during handler execution.
510 void __attribute__((noreturn)) Romain::InstanceManager::VCPU_handler(Romain::InstanceManager *m,
511 Romain::App_instance *i,
512 Romain::App_thread *t,
513 Romain::Thread_group *tg,
514 Romain::App_model *a)
516 L4vcpu::Vcpu *vcpu = t->vcpu();
517 vcpu->state()->clear(L4_VCPU_F_EXCEPTIONS | L4_VCPU_F_DEBUG_EXC);
520 Measurements::GenericEvent* ev = m->logbuf()->next();
521 ev->header.tsc = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
522 ev->header.vcpu = (l4_uint32_t)vcpu;
523 ev->header.type = Measurements::Trap;
524 ev->data.trap.start = 1;
525 ev->data.trap.trapaddr = vcpu->r()->ip;
526 ev->data.trap.trapno = vcpu->r()->trapno;
529 migrated_vCPU_handling(m, i, t, tg, a);
531 split_vCPU_handling(m, i, t, tg, a);
533 local_vCPU_handling(m, i, t, tg, a);
535 #error No vCPU handling method selected!
538 ev = m->logbuf()->next();
539 ev->header.tsc = Romain::_the_instance_manager->logbuf()->getTime(Log::logLocalTSC);
540 ev->header.vcpu = (l4_uint32_t)vcpu;
541 ev->header.type = Measurements::Trap;
542 ev->data.trap.start = 0;
543 ev->data.trap.trapno = ~0U;
545 L4::Cap<L4::Thread> self;
546 self->vcpu_resume_commit(self->vcpu_resume_start());
548 enter_kdebug("after resume");