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