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