L4Re - L4 Runtime Environment
irq
Go to the documentation of this file.
1 // vi:set ft=cpp: -*- Mode: C++ -*-
2 /**
3  * \file
4  * C++ Irq interface
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  * Alexander Warg <warg@os.inf.tu-dresden.de>
9  * economic rights: Technische Universit├Ąt Dresden (Germany)
10  *
11  * This file is part of TUD:OS and distributed under the terms of the
12  * GNU General Public License 2.
13  * Please see the COPYING-GPL-2 file for details.
14  *
15  * As a special exception, you may use this file as part of a free software
16  * library without restriction. Specifically, if other files instantiate
17  * templates or use macros or inline functions from this file, or you compile
18  * this file and link it with other files to produce an executable, this
19  * file does not by itself cause the resulting executable to be covered by
20  * the GNU General Public License. This exception does not however
21  * invalidate any other reasons why the executable file might be covered by
22  * the GNU General Public License.
23  */
24 
25 #pragma once
26 
27 #include <l4/sys/icu.h>
28 #include <l4/sys/irq.h>
29 #include <l4/sys/capability>
30 #include <l4/sys/rcv_endpoint>
31 #include <l4/sys/cxx/ipc_iface>
32 #include <l4/sys/cxx/ipc_types>
33 
34 namespace L4 {
35 
36 /**
37  * Interface for sending an acknowledge message to an object.
38  *
39  * The object is usually an ICU or an IRQ.
40  *
41  * \see L4::Icu, L4::Irq
42  */
43 class Irq_eoi : public Kobject_0t<Irq_eoi, L4::PROTO_EMPTY>
44 {
45 public:
46  /**
47  * Acknowledge the given interrupt line.
48  *
49  * \param irqnum The interrupt line that shall be acknowledged.
50  * \param[out] label If NULL this is a send-only unmask, if not
51  * NULL then this operation enters an open wait
52  * and the *protected label* shall be received here.
53  * \param to The timeout-pair (send and receive) that shall be
54  * used for this operation. The receive timeout
55  * is used with a non-NULL `label` only.
56  * \utcb{utcb}
57  *
58  * \return Syscall return tag.
59  *
60  * \note If `label` is NULL this function is a send-only operation
61  * and there is no return value except for a failed send operation.
62  * In this case use l4_ipc_error() to check for errors, **do not**
63  * use l4_error(), because l4_error() will always return an error.
64  */
65  l4_msgtag_t unmask(unsigned irqnum, l4_umword_t *label = 0,
66  l4_timeout_t to = L4_IPC_NEVER,
67  l4_utcb_t *utcb = l4_utcb()) throw()
68  {
69  return l4_icu_control_u(cap(), irqnum, L4_ICU_CTL_UNMASK, label, to, utcb);
70  }
71 };
72 
73 /**
74  * Interface that allows an object to be triggered by some source.
75  *
76  * This interface is usually used in conjunction with L4::Icu.
77  */
78 struct Triggerable : Kobject_t<Triggerable, Irq_eoi, L4_PROTO_IRQ>
79 {
80  /**
81  * Trigger.
82  *
83  * \utcb{utcb}
84  *
85  * \return Syscall return tag for a send-only operation, use l4_ipc_error()
86  * to check for errors (**do not** use l4_error()).
87  *
88  * \note This function is a send-only operation, this means there
89  * is no return value except for a failed send operation. Use
90  * l4_ipc_error() to check for errors, **do not** use l4_error(),
91  * because l4_error() will always return an error.
92  */
93  l4_msgtag_t trigger(l4_utcb_t *utcb = l4_utcb()) throw()
94  { return l4_irq_trigger_u(cap(), utcb); }
95 };
96 
97 /**
98  * C++ Irq interface.
99  *
100  * \note "IRQ" is short for "interrupt request". This is often used
101  * interchangeably for "interrupt"
102  *
103  * The Irq class provides access to abstract interrupts provided by the
104  * microkernel. Interrupts may be
105  * - hardware interrupts provided by the platform interrupt controller,
106  * - virtual device interrupts provided by the microkernel's virtual devices
107  * (virtual serial or trace buffer) or
108  * - virtual interrupts that can be triggered by user programs (IRQs)
109  *
110  * Irq objects can be created using a factory, see the L4::Factory API
111  * (L4::Factory::create()).
112  *
113  * \includefile{l4/sys/irq}
114  *
115  * For the C interface refer to the \ref l4_irq_api API for an overview.
116  */
117 class Irq : public Kobject_2t<Irq, Triggerable, Rcv_endpoint, L4_PROTO_IRQ_SENDER>
118 {
119 public:
120  using Triggerable::unmask;
121 
122  /**
123  * Attach a thread to this interrupt.
124  *
125  * \param label Identifier of the IRQ (*protected label* used for
126  * messages)
127  * \param thread Capability of the thread to attach the IRQ to.
128  * \utcb{utcb}
129  *
130  * \return Syscall return tag
131  *
132  * The *protected label* is stored in the kernel and sent to the attached
133  * thread with the IRQ-triggered notification. It allows the receiver thread
134  * to securely identify the IRQ.
135  *
136  * \deprecated Use bind_thread().
137  */
138  l4_msgtag_t attach(l4_umword_t label,
139  Cap<Thread> const &thread = Cap<Thread>::Invalid,
140  l4_utcb_t *utcb = l4_utcb()) throw()
141  L4_DEPRECATED("Use bind_thread(thread, label).")
142  {
143 #pragma GCC diagnostic push
144 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
145  return l4_irq_attach_u(cap(), label, thread.cap(), utcb);
146 #pragma GCC diagnostic pop
147  }
148 
149  /**
150  * Detach from this interrupt.
151  *
152  * \utcb{utcb}
153  *
154  * \return Syscall return tag
155  */
156  l4_msgtag_t detach(l4_utcb_t *utcb = l4_utcb()) throw()
157  { return l4_irq_detach_u(cap(), utcb); }
158 
159 
160  /**
161  * Unmask and wait for this IRQ.
162  *
163  * \param timeout Timeout.
164  * \utcb{utcb}
165  *
166  * \return Syscall return tag
167  *
168  * \note If this is the function normally used for your IRQs consider using
169  * L4::Semaphore instead of L4::Irq.
170  */
171  l4_msgtag_t receive(l4_timeout_t timeout = L4_IPC_NEVER,
172  l4_utcb_t *utcb = l4_utcb()) throw()
173  { return l4_irq_receive_u(cap(), timeout, utcb); }
174 
175  /**
176  * Unmask IRQ and (open) wait for any message.
177  *
178  * \param label The *protected label* shall be received here.
179  * \param timeout Timeout.
180  * \utcb{utcb}
181  *
182  * \return Syscall return tag
183  */
184  l4_msgtag_t wait(l4_umword_t *label, l4_timeout_t timeout = L4_IPC_NEVER,
185  l4_utcb_t *utcb = l4_utcb()) throw()
186  { return unmask(-1, label, timeout, utcb); }
187 
188  /**
189  * Unmask IRQ.
190  *
191  * \utcb{utcb}
192  *
193  * \return Syscall return tag for a send-only operation, use l4_ipc_error()
194  * to check for errors (**do not** use l4_error()).
195  *
196  * \note This function is a send-only operation, this means there is no
197  * return value except for a failed send operation. Use l4_ipc_error()
198  * to check for errors, **do not** use l4_error(), because l4_error()
199  * will always return an error.
200  *
201  * Irq::wait() and Irq::receive() operations already include an unmask(), do
202  * not use an extra unmask() in these cases.
203  *
204  * \deprecated Use L4::Irq_eoi::unmask()
205  *
206  */
207  l4_msgtag_t unmask(l4_utcb_t *utcb = l4_utcb()) throw()
208  { return unmask(-1, 0, L4_IPC_NEVER, utcb); }
209 };
210 
211 /**
212  * IRQ multiplexer for shared IRQs.
213  *
214  * This interface allows broadcasting of shared IRQs to multiple triggerables.
215  * The IRQ multiplexer is responsible for the correct mask and unmask logic for
216  * such shared IRQs.
217  *
218  * The semantics are that each of the slave IRQs is triggered whenever
219  * the multiplexer IRQ is triggered. As shared IRQs are usually
220  * level-triggered, the real IRQ source will be masked automatically
221  * when an IRQ is delivered and shall be unmasked when all attached slave
222  * IRQs are acknowledged.
223  */
224 struct Irq_mux : Kobject_t<Irq_mux, Triggerable, L4_PROTO_IRQ_MUX>
225 {
226  /**
227  * Attach an IRQ to this multiplexer.
228  *
229  * \param slave The slave that shall be attached to the master.
230  * \utcb{utcb}
231  *
232  * \return Syscall return tag
233  *
234  * The chaining feature of IRQ objects allows to deal with shared IRQs. For
235  * chaining IRQs there must be an IRQ multiplexer (Irq_mux) bound to
236  * the real IRQ source. This function allows to add slave IRQs to this
237  * multiplexer.
238  */
239  l4_msgtag_t chain(Cap<Triggerable> const &slave,
240  l4_utcb_t *utcb = l4_utcb()) throw()
241  { return l4_irq_mux_chain_u(cap(), slave.cap(), utcb); }
242 };
243 
244 
245 /**
246  * C++ Icu interface.
247  *
248  * \note "ICU" is short for "interrupt control unit".
249  *
250  * This class defines the interface for interrupt controllers. It defines
251  * functions for binding L4::Irq objects to interrupt lines, as well as
252  * functions for masking and unmasking of interrupts.
253  *
254  * To setup an interrupt line the following steps are required:
255  * 1. set_mode() (optional if interrupt has a default mode)
256  * 2. Irq::attach() to attach the interrupt capability to a thread
257  * 3. bind()
258  * 4. unmask() to receive the first interrupt
259  *
260  * \includefile{l4/sys/icu}
261  */
262 class Icu :
263  public Kobject_t<Icu, Irq_eoi, L4_PROTO_IRQ,
264  Type_info::Demand_t<1> >
265 {
266 public:
267  enum Mode
268  {
269  F_none = L4_IRQ_F_NONE,
270  F_level_high = L4_IRQ_F_LEVEL_HIGH,
271  F_level_low = L4_IRQ_F_LEVEL_LOW,
272  F_pos_edge = L4_IRQ_F_POS_EDGE,
273  F_neg_edge = L4_IRQ_F_NEG_EDGE,
274  F_both_edge = L4_IRQ_F_BOTH_EDGE,
275  F_mask = L4_IRQ_F_MASK,
276 
277  F_set_wakeup = L4_IRQ_F_SET_WAKEUP,
278  F_clear_wakeup = L4_IRQ_F_CLEAR_WAKEUP,
279  };
280 
281  enum Flags
282  {
283  F_msi = L4_ICU_FLAG_MSI
284  };
285 
286  /**
287  * This class encapsulates information about an ICU.
288  */
289  class Info : public l4_icu_info_t
290  {
291  public:
292  bool supports_msi() const { return features & F_msi; }
293  };
294 
295  /**
296  * Bind an interrupt line of an interrupt controller to an interrupt object.
297  *
298  * \param irqnum IRQ line at the ICU.
299  * \param irq IRQ object for the given IRQ line to bind to this ICU.
300  * \utcb{utcb}
301  *
302  * \return Syscall return tag. The caller should check the return value using
303  * l4_error() to check for errors and to identify the correct method
304  * for unmasking the interrupt.
305  * Return values `< 0` indicate an error. A return value of `0` means
306  * a direct unmask via the IRQ object using L4::Irq::unmask. A return
307  * value of `1` means that the interrupt has to be unmasked via the
308  * ICU using L4::Icu::unmask.
309  */
310  l4_msgtag_t bind(unsigned irqnum, L4::Cap<Triggerable> irq,
311  l4_utcb_t *utcb = l4_utcb()) throw()
312  { return l4_icu_bind_u(cap(), irqnum, irq.cap(), utcb); }
313 
314  L4_RPC_NF_OP(L4_ICU_OP_BIND,
315  l4_msgtag_t, bind, (l4_umword_t irqnum, Ipc::Cap<Irq> irq));
316 
317  /**
318  * Remove binding of an interrupt line from the interrupt controller object.
319  *
320  * \param irqnum IRQ line at the ICU.
321  * \param irq IRQ object to remove from the ICU.
322  * \utcb{utcb}
323  *
324  * \return Syscall return tag
325  */
326  l4_msgtag_t unbind(unsigned irqnum, L4::Cap<Triggerable> irq,
327  l4_utcb_t *utcb = l4_utcb()) throw()
328  { return l4_icu_unbind_u(cap(), irqnum, irq.cap(), utcb); }
329 
330  L4_RPC_NF_OP(L4_ICU_OP_UNBIND,
331  l4_msgtag_t, unbind, (l4_umword_t irqnum, Ipc::Cap<Irq> irq));
332 
333  /**
334  * Get information about the capabilities of the ICU.
335  *
336  * \param[out] info Info structure to be filled with information.
337  * \utcb{utcb}
338  *
339  * \return Syscall return tag
340  */
341  l4_msgtag_t info(l4_icu_info_t *info, l4_utcb_t *utcb = l4_utcb()) throw()
342  { return l4_icu_info_u(cap(), info, utcb); }
343 
344  struct _Info { l4_umword_t features, nr_irqs, nr_msis; };
345  L4_RPC_NF_OP(L4_ICU_OP_INFO, l4_msgtag_t, info, (_Info *info));
346 
347  /**
348  * Get MSI info about IRQ.
349  *
350  * \param irqnum IRQ line at the ICU.
351  * \param source Platform dependent requester ID for MSIs. On IA32 we
352  * use a 20bit source filter value as described in the
353  * Intel IRQ remapping specification.
354  * \param[out] msi_info A l4_icu_msi_info_t structure receiving the address
355  * and the data value to trigger this MSI.
356  *
357  * \return Syscall return tag
358  */
359  L4_INLINE_RPC_OP(L4_ICU_OP_MSI_INFO,
360  l4_msgtag_t, msi_info, (l4_umword_t irqnum, l4_uint64_t source,
361  l4_icu_msi_info_t *msi_info));
362 
363  /**
364  * \internal
365  */
366  l4_msgtag_t control(unsigned irqnum, unsigned op, l4_umword_t *label,
367  l4_timeout_t to, l4_utcb_t *utcb = l4_utcb()) throw()
368  { return l4_icu_control_u(cap(), irqnum, op, label, to, utcb); }
369 
370  /**
371  * Mask an IRQ line.
372  *
373  * \param irqnum IRQ line at the ICU.
374  * \param label If NULL this function is a send-only message to the ICU. If
375  * not NULL this function will enter an open wait after sending
376  * the mask message.
377  * \param to The timeout-pair (send and receive) that shall be used for
378  * this operation. The receive timeout is used with a non-NULL
379  * `label` only.
380  * \utcb{utcb}
381  *
382  * \return Syscall return tag
383  */
384  l4_msgtag_t mask(unsigned irqnum,
385  l4_umword_t *label = 0,
386  l4_timeout_t to = L4_IPC_NEVER,
387  l4_utcb_t *utcb = l4_utcb()) throw()
388  { return l4_icu_mask_u(cap(), irqnum, label, to, utcb); }
389 
390  L4_RPC_NF_OP(L4_ICU_OP_MASK, l4_msgtag_t, mask, (l4_umword_t irqnum),
391  L4::Ipc::Send_only);
392 
393 
394  L4_RPC_NF_OP(L4_ICU_OP_UNMASK, l4_msgtag_t, unmask, (l4_umword_t irqnum),
395  L4::Ipc::Send_only);
396 
397  /**
398  * Set interrupt mode.
399  *
400  * \param irqnum IRQ line at the ICU.
401  * \param mode Mode, see #L4_irq_mode.
402  * \utcb{utcb}
403  *
404  * \return Syscall return tag
405  */
406  l4_msgtag_t set_mode(unsigned irqnum, l4_umword_t mode,
407  l4_utcb_t *utcb = l4_utcb()) throw()
408  { return l4_icu_set_mode_u(cap(), irqnum, mode, utcb); }
409 
410  L4_RPC_NF_OP(L4_ICU_OP_SET_MODE,
411  l4_msgtag_t, set_mode, (l4_umword_t irqnum, l4_umword_t mode));
412 
413  typedef L4::Typeid::Rpcs_sys<
414  bind_t, unbind_t, info_t, msi_info_t, unmask_t, mask_t, set_mode_t
415  > Rpcs;
416 };
417 
418 }