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 //-----------------------------------------------------------------------------
87 static unsigned irq_log_fmt(Tb_entry *, int, char *)
88 asm ("__irq_log_fmt");
93 //-----------------------------------------------------------------------------
99 #include "entry_frame.h"
101 #include "ipc_sender.h"
103 #include "kmem_slab.h"
104 #include "lock_guard.h"
105 #include "receiver.h"
106 #include "std_macros.h"
108 #include "thread_lock.h"
109 #include "thread_state.h"
110 #include "l4_buf_iter.h"
112 FIASCO_DEFINE_KOBJ(Irq);
114 static Irq_base *irq_base_dcast(Kobject_iface *o)
115 { return Kobject::dcast<Irq*>(o); }
120 { Irq_base::dcast = &irq_base_dcast; }
123 static Irq_base_cast register_irq_base_cast;
128 Irq::self(Irq_pin const *pin)
130 #define MYoffsetof(TYPE, MEMBER) (((size_t) &((TYPE *)10)->MEMBER) - 10)
131 return reinterpret_cast<Irq*>(reinterpret_cast<Mword>(pin)
132 - MYoffsetof(Irq, _pin));
138 PUBLIC inline explicit
139 Chain_irq_pin::Chain_irq_pin(Irq *i)
140 { payload()[0] = Mword(i); }
144 Chain_irq_pin::irq() const
145 { return (Irq*)payload()[0]; }
149 Chain_irq_pin::do_unmask()
153 old = irq()->_queued;
154 while (!mp_cas(&irq()->_queued, old, old - 1));
157 irq()->pin()->unmask();
163 Chain_irq_pin::do_mask()
167 old = irq()->_queued;
168 while (!mp_cas(&irq()->_queued, old, old + 1));
171 irq()->pin()->mask();
177 Chain_irq_pin::unbind_irq()
179 Irq_base *self = Irq::self(this);
181 for (n = irq(); n->_next && n->_next != self; n = n->_next)
184 assert (n->_next == self);
185 n->_next = n->_next->_next;
189 replace<Sw_irq_pin>();
195 Chain_irq_pin::do_mask_and_ack()
200 PUBLIC inline NOEXPORT
202 Irq::operator new (size_t, void *p)
207 Irq::operator delete (void *_l)
209 Irq *l = reinterpret_cast<Irq*>(_l);
211 l->_q->free(sizeof(Irq));
213 allocator()->free(l);
218 Irq::allocate(Ram_quota *q)
221 if (q->alloc(sizeof(Irq)) && (nq = allocator()->alloc()))
222 return new (nq) Irq(q);
227 PRIVATE static inline NOEXPORT NEEDS["kmem_slab.h"]
231 static Allocator* slabs =
232 new Kmem_slab_simple (sizeof (Irq), __alignof__ (Irq), "Irq");
241 { return _irq_thread; }
244 /** Bind a receiver to this device interrupt.
245 @param t the receiver that wants to receive IPC messages for this IRQ
246 @return true if the binding could be established
248 PUBLIC inline NEEDS ["atomic.h", "cpu_lock.h", "lock_guard.h"]
250 Irq::alloc(Receiver *t)
252 bool ret = cas (&_irq_thread, reinterpret_cast<Receiver*>(0), t);
256 if (EXPECT_TRUE(t && t != (Receiver*)~0UL)) // handle attaching the JDB
259 pin()->set_cpu(t->cpu());
269 /** Release an device interrupt.
270 @param t the receiver that ownes the IRQ
271 @return true if t really was the owner of the IRQ and operation was
276 Irq::free(Receiver *t)
278 bool ret = cas (&_irq_thread, t, reinterpret_cast<Receiver*>(0));
283 Lock_guard<Cpu_lock> guard(&cpu_lock);
287 if (EXPECT_TRUE(t != 0))
289 sender_dequeue(t->sender_list());
290 t->vcpu_update_state();
292 if (t->dec_ref() == 0)
301 PUBLIC explicit inline
302 Irq::Irq(Ram_quota *q = 0)
303 : _queued(0), _irq_thread(0), _irq_id(~0UL), _q(q)
305 new (pin()) Sw_irq_pin();
311 Irq::destroy(Kobject ***rl)
317 Lock_guard<Cpu_lock> g(&cpu_lock);
319 pin()->replace<Sw_irq_pin>();
322 Kobject::destroy(rl);
328 { return pin()->payload()[0]; }
330 /** Consume one interrupt.
331 @return number of IRQs that are still pending.
333 PRIVATE inline NEEDS ["atomic.h"]
343 while (!mp_cas (&_queued, old, old - 1));
348 PUBLIC inline NEEDS[Irq::consume]
357 * Predicate used to figure out if the sender shall be enqueued
358 * for sending a second message after sending the first.
362 Irq::requeue_sender()
363 { return consume() > 0; }
366 * Predicate used to figure out if the sender shall be deqeued after
367 * sending the request.
371 Irq::dequeue_sender()
372 { return consume() < 1; }
378 Syscall_frame* dst_regs = _irq_thread->rcv_regs();
380 // set ipc return value: OK
381 dst_regs->tag(L4_msg_tag(0, 0, 0, L4_msg_tag::Label_irq));
383 // set ipc source thread id
384 dst_regs->from(_irq_id);
390 Irq::modify_label(Mword const *todo, int cnt)
392 for (int i = 0; i < cnt*4; i += 4)
394 Mword const test_mask = todo[i];
395 Mword const test = todo[i+1];
396 if ((_irq_id & test_mask) == test)
398 Mword const set_mask = todo[i+2];
399 Mword const set = todo[i+3];
401 _irq_id = (_irq_id & ~set_mask) | set;
410 Irq::handle_remote_hit(Context::Drq *, Context *, void *arg)
412 Irq *irq = (Irq*)arg;
413 irq->pin()->set_cpu(current_cpu());
414 irq->send_msg(irq->_irq_thread);
415 return Context::Drq::No_answer;
420 Irq::handle_chained_irq()
422 if (EXPECT_FALSE (!Irq_base::_next))
426 for (Irq_base *n = Irq_base::_next; n;)
428 Irq *i = nonull_static_cast<Irq*>(n);
434 n = i->Irq_base::_next;
441 while (!mp_cas(&_queued, old, old + irqs));
444 for (Irq_base *n = Irq_base::_next; n;)
446 Irq *i = nonull_static_cast<Irq*>(n);
449 n = i->Irq_base::_next;
453 PUBLIC inline NEEDS[Irq::handle_chained_irq]
457 // We're entered holding the kernel lock, which also means irqs are
458 // disabled on this CPU (XXX always correct?). We never enable irqs
459 // in this stack frame (except maybe in a nonnested invocation of
460 // switch_exec() -> switchin_context()) -- they will be re-enabled
461 // once we return from it (iret in entry.S:all_irqs) or we switch to
462 // a different thread.
464 // LOG_MSG_3VAL(current(), "IRQ", dbg_id(), 0, _queued);
466 assert (cpu_lock.test());
467 pin()->mask_and_ack();
469 if (EXPECT_FALSE (!_irq_thread))
471 handle_chained_irq();
474 else if (EXPECT_FALSE (_irq_thread == (void*)-1))
476 // debugger attached to IRQ
477 #if defined(CONFIG_KDB) || defined(CONFIG_JDB)
478 if (pin()->check_debug_irq())
489 while (!mp_cas(&_queued, old, old + 1));
491 if (EXPECT_TRUE (old == 0)) // increase hit counter
493 if (EXPECT_FALSE(_irq_thread->cpu() != current_cpu()))
494 _irq_thread->drq(&_drq, handle_remote_hit, this, 0,
495 Context::Drq::Target_ctxt, Context::Drq::No_wait);
497 send_msg(_irq_thread);
503 Irq::sys_attach(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /*f*/,
506 L4_snd_item_iter snd_items(utcb, tag.words());
508 Receiver *thread = 0;
509 unsigned mode = utcb->values[0] >> 16;
511 if (tag.items() == 0)
514 if (mode & Set_irq_mode)
515 printf("DEPRECATED SET IRQ MODE\n");
516 //pin()->set_mode(mode);
522 return commit_result(0);
525 if (tag.items() && snd_items.next())
527 L4_fpage bind_thread(snd_items.get()->d);
528 if (EXPECT_FALSE(!bind_thread.is_objpage()))
529 return commit_error(utcb, L4_error::Overflow);
531 thread = Kobject::dcast<Thread*>(o_space->lookup_local(bind_thread.obj_index()));
535 thread = current_thread();
539 if (mode & Set_irq_mode)
540 printf("DEPRECATED SET IRQ MODE\n");
541 _irq_id = utcb->values[1];
542 return commit_result(0);
545 return commit_result(-L4_err::EInval);
550 Irq::sys_chain(L4_msg_tag const &tag, Utcb const *utcb, Syscall_frame * /*f*/,
553 L4_snd_item_iter snd_items(utcb, tag.words());
556 unsigned mode = utcb->values[0] >> 16;
558 if (tag.items() == 0 || _irq_thread)
559 return commit_result(-L4_err::EInval);
561 if (tag.items() && snd_items.next())
563 L4_fpage bind_irq(snd_items.get()->d);
564 if (EXPECT_FALSE(!bind_irq.is_objpage()))
565 return commit_error(utcb, L4_error::Overflow);
567 irq = Kobject::dcast<Irq*>(o_space->lookup_local(bind_irq.obj_index()));
571 return commit_result(-L4_err::EInval);
573 if (mode & Set_irq_mode)
574 printf("DEPRECATED SET IRQ MODE\n");
575 //pin()->set_mode(mode);
577 irq->pin()->unbind_irq();
579 if (!irq->pin()->masked())
584 while (!mp_cas(&_queued, old, old + 1));
587 irq->pin()->replace<Chain_irq_pin>(this);
589 irq->Irq_base::_next = Irq_base::_next;
590 Irq_base::_next = irq;
592 return commit_result(0);
597 Irq::kinvoke(L4_obj_ref, Mword /*rights*/, Syscall_frame *f,
598 Utcb const *utcb, Utcb *)
600 register Context *const c_thread = ::current();
601 register Space *const c_space = c_thread->space();
602 register Obj_space *const o_space = c_space->obj_space();
604 L4_msg_tag tag = f->tag();
606 if (EXPECT_FALSE(tag.proto() != L4_msg_tag::Label_irq))
607 return commit_result(-L4_err::EBadproto);
609 if (EXPECT_FALSE(tag.words() < 1))
610 return commit_result(-L4_err::EInval);
612 switch ((utcb->values[0] & 0xffff))
618 case Op_attach: /* ATTACH, DETACH */
619 return sys_attach(tag, utcb, f, o_space);
621 return sys_chain(tag, utcb, f, o_space);
623 if (pin()->trigger())
625 Irq::log_irq(this, 0);
630 return commit_result(-L4_err::EInval);
640 // --------------------------------------------------------------------------
641 IMPLEMENTATION [debug]:
645 Chain_irq_pin::pin_type() const
646 { return "CHAIN IRQ"; }
650 Irq::irq_log_fmt(Tb_entry *e, int maxlen, char *buf)
652 Irq_log *l = e->payload<Irq_log>();
653 return snprintf(buf, maxlen, "0x%x/%u D:%lx", l->irq_number, l->irq_number,
659 Irq::log_irq(Irq *irq, int nr)
661 LOG_TRACE("IRQ-HW", "irq-hw", current(), __irq_log_fmt,
662 Irq::Irq_log *l = tbe->payload<Irq::Irq_log>();
664 l->irq_obj = irq ? irq->dbg_id() : ~0UL;
668 PUBLIC static inline NEEDS["config.h"]
670 Irq::log_timer_irq(int nr)
672 LOG_TRACE("IRQ-Timer", "irq-ti", current(), __irq_log_fmt,
673 Irq::Irq_log *l = tbe->payload<Irq::Irq_log>();
679 // --------------------------------------------------------------------------
680 IMPLEMENTATION [!debug]:
684 Irq::log_irq(Irq *, int)
689 Irq::log_timer_irq(int)