3 #include "ipc_sender.h"
5 #include "kobject_helper.h"
6 #include "member_offs.h"
15 /** Hardware interrupts. This class encapsulates handware IRQs. Also,
16 it provides a registry that ensures that only one receiver can sign up
17 to receive interrupt IPC messages.
21 public Ipc_sender<Irq>,
22 public Kobject_h<Irq>,
25 FIASCO_DECLARE_KOBJ();
28 friend class Chain_irq_pin;
31 typedef slab_cache_anon Allocator;
57 Receiver *_irq_thread;
72 class Chain_irq_pin : public Sw_irq_pin
75 //-----------------------------------------------------------------------------
88 static unsigned irq_log_fmt(Tb_entry *, int, char *)
89 asm ("__irq_log_fmt");
94 //-----------------------------------------------------------------------------
100 #include "entry_frame.h"
102 #include "ipc_sender.h"
104 #include "kmem_slab.h"
105 #include "lock_guard.h"
106 #include "receiver.h"
107 #include "std_macros.h"
108 #include "thread_object.h"
109 #include "thread_lock.h"
110 #include "thread_state.h"
111 #include "l4_buf_iter.h"
113 FIASCO_DEFINE_KOBJ(Irq);
115 static Irq_base *irq_base_dcast(Kobject_iface *o)
116 { return Kobject::dcast<Irq*>(o); }
121 { Irq_base::dcast = &irq_base_dcast; }
124 static Irq_base_cast register_irq_base_cast;
129 Irq::self(Irq_pin const *pin)
131 #define MYoffsetof(TYPE, MEMBER) (((size_t) &((TYPE *)10)->MEMBER) - 10)
132 return reinterpret_cast<Irq*>(reinterpret_cast<Mword>(pin)
133 - MYoffsetof(Irq, _pin));
139 PUBLIC inline explicit
140 Chain_irq_pin::Chain_irq_pin(Irq *i)
141 { payload()[0] = Mword(i); }
145 Chain_irq_pin::irq() const
146 { return (Irq*)payload()[0]; }
150 Chain_irq_pin::do_unmask()
154 old = irq()->_queued;
155 while (!mp_cas(&irq()->_queued, old, old - 1));
158 irq()->pin()->unmask();
164 Chain_irq_pin::do_mask()
168 old = irq()->_queued;
169 while (!mp_cas(&irq()->_queued, old, old + 1));
172 irq()->pin()->mask();
178 Chain_irq_pin::unbind_irq()
180 Irq_base *self = Irq::self(this);
182 for (n = irq(); n->_next && n->_next != self; n = n->_next)
185 assert (n->_next == self);
186 n->_next = n->_next->_next;
190 replace<Sw_irq_pin>();
196 Chain_irq_pin::do_mask_and_ack()
201 PUBLIC inline NOEXPORT
203 Irq::operator new (size_t, void *p)
208 Irq::operator delete (void *_l)
210 Irq *l = reinterpret_cast<Irq*>(_l);
212 l->_q->free(sizeof(Irq));
214 allocator()->free(l);
219 Irq::allocate(Ram_quota *q)
222 if (q->alloc(sizeof(Irq)) && (nq = allocator()->alloc()))
223 return new (nq) Irq(q);
228 PRIVATE static inline NOEXPORT NEEDS["kmem_slab.h"]
232 static Allocator* slabs =
233 new Kmem_slab_simple (sizeof (Irq), __alignof__ (Irq), "Irq");
242 { return _irq_thread; }
245 /** Bind a receiver to this device interrupt.
246 @param t the receiver that wants to receive IPC messages for this IRQ
247 @return true if the binding could be established
249 PUBLIC inline NEEDS ["atomic.h", "cpu_lock.h", "lock_guard.h"]
251 Irq::alloc(Receiver *t)
253 bool ret = cas (&_irq_thread, reinterpret_cast<Receiver*>(0), t);
257 if (EXPECT_TRUE(t && t != (Receiver*)~0UL)) // handle attaching the JDB
260 pin()->set_cpu(t->cpu());
270 /** Release an device interrupt.
271 @param t the receiver that ownes the IRQ
272 @return true if t really was the owner of the IRQ and operation was
277 Irq::free(Receiver *t)
279 bool ret = cas (&_irq_thread, t, reinterpret_cast<Receiver*>(0));
284 Lock_guard<Cpu_lock> guard(&cpu_lock);
288 if (EXPECT_TRUE(t != 0))
290 sender_dequeue(t->sender_list());
291 t->vcpu_update_state();
293 if (t->dec_ref() == 0)
302 PUBLIC explicit inline
303 Irq::Irq(Ram_quota *q = 0)
304 : _queued(0), _irq_thread(0), _irq_id(~0UL), _q(q)
306 new (pin()) Sw_irq_pin();
312 Irq::destroy(Kobject ***rl)
318 Lock_guard<Cpu_lock> g(&cpu_lock);
320 pin()->replace<Sw_irq_pin>();
323 Kobject::destroy(rl);
329 { return pin()->payload()[0]; }
331 /** Consume one interrupt.
332 @return number of IRQs that are still pending.
334 PRIVATE inline NEEDS ["atomic.h"]
344 while (!mp_cas (&_queued, old, old - 1));
349 PUBLIC inline NEEDS[Irq::consume]
358 * Predicate used to figure out if the sender shall be enqueued
359 * for sending a second message after sending the first.
363 Irq::requeue_sender()
364 { return consume() > 0; }
367 * Predicate used to figure out if the sender shall be deqeued after
368 * sending the request.
372 Irq::dequeue_sender()
373 { return consume() < 1; }
379 Syscall_frame* dst_regs = _irq_thread->rcv_regs();
381 // set ipc return value: OK
382 dst_regs->tag(L4_msg_tag(0, 0, 0, L4_msg_tag::Label_irq));
384 // set ipc source thread id
385 dst_regs->from(_irq_id);
391 Irq::modify_label(Mword const *todo, int cnt)
393 for (int i = 0; i < cnt*4; i += 4)
395 Mword const test_mask = todo[i];
396 Mword const test = todo[i+1];
397 if ((_irq_id & test_mask) == test)
399 Mword const set_mask = todo[i+2];
400 Mword const set = todo[i+3];
402 _irq_id = (_irq_id & ~set_mask) | set;
411 Irq::handle_remote_hit(Context::Drq *, Context *, void *arg)
413 Irq *irq = (Irq*)arg;
414 irq->pin()->set_cpu(current_cpu());
415 irq->send_msg(irq->_irq_thread);
416 return Context::Drq::No_answer;
421 Irq::handle_chained_irq()
423 if (EXPECT_FALSE (!Irq_base::_next))
427 for (Irq_base *n = Irq_base::_next; n;)
429 Irq *i = nonull_static_cast<Irq*>(n);
435 n = i->Irq_base::_next;
442 while (!mp_cas(&_queued, old, old + irqs));
445 for (Irq_base *n = Irq_base::_next; n;)
447 Irq *i = nonull_static_cast<Irq*>(n);
450 n = i->Irq_base::_next;
454 PUBLIC inline NEEDS[Irq::handle_chained_irq]
458 // We're entered holding the kernel lock, which also means irqs are
459 // disabled on this CPU (XXX always correct?). We never enable irqs
460 // in this stack frame (except maybe in a nonnested invocation of
461 // switch_exec() -> switchin_context()) -- they will be re-enabled
462 // once we return from it (iret in entry.S:all_irqs) or we switch to
463 // a different thread.
465 // LOG_MSG_3VAL(current(), "IRQ", dbg_id(), 0, _queued);
467 assert (cpu_lock.test());
468 pin()->mask_and_ack();
470 if (EXPECT_FALSE (!_irq_thread))
472 handle_chained_irq();
475 else if (EXPECT_FALSE (_irq_thread == (void*)-1))
477 // debugger attached to IRQ
478 #if defined(CONFIG_KDB) || defined(CONFIG_JDB)
479 if (pin()->check_debug_irq())
490 while (!mp_cas(&_queued, old, old + 1));
492 if (EXPECT_TRUE (old == 0)) // increase hit counter
494 if (EXPECT_FALSE(_irq_thread->cpu() != current_cpu()))
495 _irq_thread->drq(&_drq, handle_remote_hit, this, 0,
496 Context::Drq::Target_ctxt, Context::Drq::No_wait);
498 send_msg(_irq_thread);
504 Irq::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /*f*/,
507 L4_snd_item_iter snd_items(utcb, tag.words());
509 Receiver *thread = 0;
510 unsigned mode = utcb->values[0] >> 16;
512 if (tag.items() == 0)
515 if (mode & Set_irq_mode)
516 printf("DEPRECATED SET IRQ MODE\n");
517 //pin()->set_mode(mode);
523 return commit_result(0);
526 if (tag.items() && snd_items.next())
528 L4_fpage bind_thread(snd_items.get()->d);
529 if (EXPECT_FALSE(!bind_thread.is_objpage()))
530 return commit_error(utcb, L4_error::Overflow);
532 thread = Kobject::dcast<Thread_object*>(o_space->lookup_local(bind_thread.obj_index()));
536 thread = current_thread();
540 if (mode & Set_irq_mode)
541 printf("DEPRECATED SET IRQ MODE\n");
542 _irq_id = utcb->values[1];
543 return commit_result(0);
546 return commit_result(-L4_err::EInval);
551 Irq::sys_chain(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /*f*/,
554 L4_snd_item_iter snd_items(utcb, tag.words());
557 unsigned mode = utcb->values[0] >> 16;
559 if (tag.items() == 0 || _irq_thread)
560 return commit_result(-L4_err::EInval);
562 if (tag.items() && snd_items.next())
564 L4_fpage bind_irq(snd_items.get()->d);
565 if (EXPECT_FALSE(!bind_irq.is_objpage()))
566 return commit_error(utcb, L4_error::Overflow);
568 irq = Kobject::dcast<Irq*>(o_space->lookup_local(bind_irq.obj_index()));
572 return commit_result(-L4_err::EInval);
574 if (mode & Set_irq_mode)
575 printf("DEPRECATED SET IRQ MODE\n");
576 //pin()->set_mode(mode);
578 irq->pin()->unbind_irq();
580 if (!irq->pin()->masked())
585 while (!mp_cas(&_queued, old, old + 1));
588 irq->pin()->replace<Chain_irq_pin>(this);
590 irq->Irq_base::_next = Irq_base::_next;
591 Irq_base::_next = irq;
593 return commit_result(0);
598 Irq::kinvoke(L4_obj_ref, Mword /*rights*/, Syscall_frame *f,
599 Utcb const *utcb, Utcb *)
601 register Context *const c_thread = ::current();
602 register Space *const c_space = c_thread->space();
603 register Obj_space *const o_space = c_space->obj_space();
605 L4_msg_tag tag = f->tag();
607 if (EXPECT_FALSE(tag.proto() != L4_msg_tag::Label_irq))
608 return commit_result(-L4_err::EBadproto);
610 if (EXPECT_FALSE(tag.words() < 1))
611 return commit_result(-L4_err::EInval);
613 switch ((utcb->values[0] & 0xffff))
619 case Op_attach: /* ATTACH, DETACH */
620 return sys_attach(tag, utcb, f, o_space);
622 return sys_chain(tag, utcb, f, o_space);
624 if (pin()->trigger())
626 Irq::log_irq(this, 0);
631 return commit_result(-L4_err::EInval);
641 // --------------------------------------------------------------------------
642 IMPLEMENTATION [debug]:
648 Chain_irq_pin::pin_type() const
649 { return "CHAIN IRQ"; }
653 Irq::irq_log_fmt(Tb_entry *e, int maxlen, char *buf)
655 Irq_log *l = e->payload<Irq_log>();
656 return snprintf(buf, maxlen, "0x%x/%u D:%lx userip=%lx",
657 l->irq_number, l->irq_number,
658 l->irq_obj, l->user_ip);
663 Irq::log_irq(Irq *irq, int nr)
665 Context *c = current();
666 LOG_TRACE("IRQ-Object triggers", "irq", c, __irq_log_fmt,
667 Irq::Irq_log *l = tbe->payload<Irq::Irq_log>();
669 l->user_ip = c->regs()->ip(),
670 l->irq_obj = irq ? irq->dbg_id() : ~0UL;
674 PUBLIC static inline NEEDS["config.h"]
676 Irq::log_timer_irq(int nr)
678 Context *c = current();
679 LOG_TRACE("Kernel Timer Events", "timer", c, __irq_log_fmt,
680 Irq::Irq_log *l = tbe->payload<Irq::Irq_log>();
682 l->user_ip = c->regs()->ip(),
687 // --------------------------------------------------------------------------
688 IMPLEMENTATION [!debug]:
692 Irq::log_irq(Irq *, int)
697 Irq::log_timer_irq(int)