1 /**
2  * \file
3  * C Irq interface
4  * \ingroup l4_api
5  */
6 /*
7  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
8  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
9  *               Björn Döbel <doebel@os.inf.tu-dresden.de>
10  *     economic rights: Technische Universität Dresden (Germany)
11  *
12  * This file is part of TUD:OS and distributed under the terms of the
13  * GNU General Public License 2.
14  * Please see the COPYING-GPL-2 file for details.
15  *
16  * As a special exception, you may use this file as part of a free software
17  * library without restriction.  Specifically, if other files instantiate
18  * templates or use macros or inline functions from this file, or you compile
19  * this file and link it with other files to produce an executable, this
20  * file does not by itself cause the resulting executable to be covered by
21  * the GNU General Public License.  This exception does not however
22  * invalidate any other reasons why the executable file might be covered by
23  * the GNU General Public License.
24  */
25 #pragma once
26 
27 #include <l4/sys/kernel_object.h>
28 #include <l4/sys/ipc.h>
29 #include <l4/sys/rcv_endpoint.h>
30 
31 /**
32  * \defgroup l4_irq_api IRQs
33  * \ingroup  l4_kernel_object_api
34  *
35  * C IRQ interface.
36  *
37  * The IRQ interface provides access to abstract interrupts provided by the
38  * microkernel. Interrupts may be
39  * - hardware interrupts provided by the platform interrupt controller,
40  * - virtual device interrupts provided by the microkernel's virtual devices
41  *   (virtual serial or trace buffer) or
42  * - virtual interrupts that can be triggered by user programs (IRQs) via
43  *   l4_irq_trigger().
44  *
45  * IRQ objects can be created using a factory, see the \ref l4_factory_api API
46  * (use l4_factory_create_irq()).
47  *
48  * \includefile{l4/sys/irq.h}
49  *
50  * For the C++ interface refer to the L4::Irq API for an overview.
51  */
52 
53 /**
54  * Chain an IRQ to another master IRQ source.
55  * \ingroup l4_irq_api
56  *
57  * \param irq    The master IRQ object.
58  * \param slave  The slave that shall be attached to the master.
59  *
60  * \return Syscall return tag
61  *
62  * The chaining feature of IRQ objects allows to deal with shared IRQs. For
63  * chaining IRQs there must be a master IRQ object, bound to the real IRQ
64  * source. Note, the master IRQ must not have a thread bound to it.
65  *
66  * This function allows to add a limited number of slave IRQs to this master
67  * IRQ, with the semantics that each of the slave IRQs is triggered whenever
68  * the master IRQ is triggered. The master IRQ will be masked automatically
69  * when an IRQ is delivered and shall be unmasked when all attached slave IRQs
70  * are unmasked.
71  */
72 L4_INLINE l4_msgtag_t
73 l4_irq_mux_chain(l4_cap_idx_t irq, l4_cap_idx_t slave) L4_NOTHROW;
74 
75 /**
76  * \ingroup l4_irq_api
77  * \copybrief L4::Irq_mux::chain
78  * \param irq  The master IRQ object.
79  * \copydetails L4::Irq_mux::chain
80  */
81 L4_INLINE l4_msgtag_t
82 l4_irq_mux_chain_u(l4_cap_idx_t irq, l4_cap_idx_t slave,
83                    l4_utcb_t *utcb) L4_NOTHROW;
84 
85 /**
86  * Detach from an interrupt source.
87  * \ingroup l4_irq_api
88  *
89  * \param irq  The IRQ object that shall be detached.
90  *
91  * \return Syscall return tag
92  */
93 L4_INLINE l4_msgtag_t
94 l4_irq_detach(l4_cap_idx_t irq) L4_NOTHROW;
95 
96 /**
97  * \ingroup l4_irq_api
98  * \copybrief L4::Irq::detach
99  * \param irq  The IRQ object that shall be detached.
100  * \copydetails L4::Irq::detach
101  */
102 L4_INLINE l4_msgtag_t
103 l4_irq_detach_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
104 
105 
106 /**
107  * Trigger an IRQ.
108  * \ingroup l4_irq_api
109  *
110  * \param irq  The IRQ object that shall be triggered.
111  *
112  * \return Syscall return tag.
113  *
114  * Note that this function is a send only operation, i.e. there is no return
115  * value except for a failed send operation. Especially l4_error() will
116  * return an error value from the message tag which still contains the IRQ
117  * protocol used for the send operation.
118  *
119  * Use l4_ipc_error() to check for (send) errors.
120  */
121 L4_INLINE l4_msgtag_t
122 l4_irq_trigger(l4_cap_idx_t irq) L4_NOTHROW;
123 
124 /**
125  * \ingroup l4_irq_api
126  * \copybrief L4::Irq::trigger
127  * \param irq  The IRQ object that shall be triggered.
128  * \copydetails L4::Irq::trigger
129  */
130 L4_INLINE l4_msgtag_t
131 l4_irq_trigger_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
132 
133 /**
134  * Unmask and wait for specified IRQ.
135  * \ingroup l4_irq_api
136  *
137  * \param irq  The IRQ object that shall be unmasked.
138  * \param to   Timeout.
139  *
140  * \return Syscall return tag
141  */
142 L4_INLINE l4_msgtag_t
143 l4_irq_receive(l4_cap_idx_t irq, l4_timeout_t to) L4_NOTHROW;
144 
145 /**
146  * \ingroup l4_irq_api
147  * \copybrief L4::Irq::receive
148  * \param irq  The IRQ object that shall be unmasked.
149  * \copydetails L4::Irq::receive
150  */
151 L4_INLINE l4_msgtag_t
152 l4_irq_receive_u(l4_cap_idx_t irq, l4_timeout_t timeout, l4_utcb_t *utcb) L4_NOTHROW;
153 
154 /**
155  * Unmask IRQ and wait for any message.
156  * \ingroup l4_irq_api
157  *
158  * \param irq    The IRQ object that shall be unmasked.
159  * \param label  Receive label.
160  * \param to     Timeout.
161  *
162  * \return Syscall return tag
163  */
164 L4_INLINE l4_msgtag_t
165 l4_irq_wait(l4_cap_idx_t irq, l4_umword_t *label,
166             l4_timeout_t to) L4_NOTHROW;
167 
168 /**
169  * \ingroup l4_irq_api
170  * \copybrief L4::Irq::wait
171  * \param irq  The IRQ object that shall be unmasked.
172  * \copydetails L4::Irq::wait
173  */
174 L4_INLINE l4_msgtag_t
175 l4_irq_wait_u(l4_cap_idx_t irq, l4_umword_t *label,
176               l4_timeout_t timeout, l4_utcb_t *utcb) L4_NOTHROW;
177 
178 /**
179  * Unmask IRQ.
180  * \ingroup l4_irq_api
181  *
182  * \param irq  The IRQ object that shall be unmasked.
183  *
184  * \return Syscall return tag
185  *
186  * \note l4_irq_wait() and l4_irq_receive() are doing the unmask themselves.
187  */
188 L4_INLINE l4_msgtag_t
189 l4_irq_unmask(l4_cap_idx_t irq) L4_NOTHROW;
190 
191 /**
192  * \ingroup l4_irq_api
193  * \copybrief L4::Irq::unmask
194  * \param irq  The IRQ object that shall be unmasked.
195  * \copydetails L4::Irq::unmask
196  */
197 L4_INLINE l4_msgtag_t
198 l4_irq_unmask_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW;
199 
200 /**
201  * \internal
202  */
203 enum L4_irq_sender_op
204 {
205   L4_IRQ_SENDER_OP_RESERVED1 = 0, // Ex ATTACH
206   L4_IRQ_SENDER_OP_DETACH    = 1
207 };
208 
209 /**
210  * \internal
211  */
212 enum L4_irq_mux_op
213 {
214   L4_IRQ_MUX_OP_CHAIN = 0
215 };
216 
217 /**
218  * \internal
219  */
220 enum L4_irq_op
221 {
222   L4_IRQ_OP_TRIGGER   = 2,
223   L4_IRQ_OP_EOI       = 4
224 };
225 
226 /**************************************************************************
227  * Implementations
228  */
229 
230 L4_INLINE l4_msgtag_t
l4_irq_mux_chain_u(l4_cap_idx_t irq,l4_cap_idx_t slave,l4_utcb_t * utcb)231 l4_irq_mux_chain_u(l4_cap_idx_t irq, l4_cap_idx_t slave,
232                    l4_utcb_t *utcb) L4_NOTHROW
233 {
234   l4_msg_regs_t *m = l4_utcb_mr_u(utcb);
235   m->mr[0] = L4_IRQ_MUX_OP_CHAIN;
236   m->mr[1] = l4_map_obj_control(0, 0);
237   m->mr[2] = l4_obj_fpage(slave, 0, L4_CAP_FPAGE_RWS).raw;
238   return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ_MUX, 1, 1, 0),
239                      L4_IPC_NEVER);
240 }
241 
242 L4_INLINE l4_msgtag_t
l4_irq_detach_u(l4_cap_idx_t irq,l4_utcb_t * utcb)243 l4_irq_detach_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
244 {
245   l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_SENDER_OP_DETACH;
246   return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ_SENDER, 1, 0, 0),
247                      L4_IPC_NEVER);
248 }
249 
250 L4_INLINE l4_msgtag_t
l4_irq_trigger_u(l4_cap_idx_t irq,l4_utcb_t * utcb)251 l4_irq_trigger_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
252 {
253   return l4_ipc_send(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 0, 0, 0),
254                      L4_IPC_BOTH_TIMEOUT_0);
255 }
256 
257 L4_INLINE l4_msgtag_t
l4_irq_receive_u(l4_cap_idx_t irq,l4_timeout_t to,l4_utcb_t * utcb)258 l4_irq_receive_u(l4_cap_idx_t irq, l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
259 {
260   l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
261   return l4_ipc_call(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), to);
262 }
263 
264 L4_INLINE l4_msgtag_t
l4_irq_wait_u(l4_cap_idx_t irq,l4_umword_t * label,l4_timeout_t to,l4_utcb_t * utcb)265 l4_irq_wait_u(l4_cap_idx_t irq, l4_umword_t *label,
266             l4_timeout_t to, l4_utcb_t *utcb) L4_NOTHROW
267 {
268   l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
269   return l4_ipc_send_and_wait(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0),
270                               label, to);
271 }
272 
273 L4_INLINE l4_msgtag_t
l4_irq_unmask_u(l4_cap_idx_t irq,l4_utcb_t * utcb)274 l4_irq_unmask_u(l4_cap_idx_t irq, l4_utcb_t *utcb) L4_NOTHROW
275 {
276   l4_utcb_mr_u(utcb)->mr[0] = L4_IRQ_OP_EOI;
277   return l4_ipc_send(irq, utcb, l4_msgtag(L4_PROTO_IRQ, 1, 0, 0), L4_IPC_NEVER);
278 }
279 
280 
281 L4_INLINE l4_msgtag_t
l4_irq_mux_chain(l4_cap_idx_t irq,l4_cap_idx_t slave)282 l4_irq_mux_chain(l4_cap_idx_t irq, l4_cap_idx_t slave) L4_NOTHROW
283 {
284   return l4_irq_mux_chain_u(irq, slave, l4_utcb());
285 }
286 
287 L4_INLINE l4_msgtag_t
l4_irq_detach(l4_cap_idx_t irq)288 l4_irq_detach(l4_cap_idx_t irq) L4_NOTHROW
289 {
290   return l4_irq_detach_u(irq, l4_utcb());
291 }
292 
293 L4_INLINE l4_msgtag_t
l4_irq_trigger(l4_cap_idx_t irq)294 l4_irq_trigger(l4_cap_idx_t irq) L4_NOTHROW
295 {
296   return l4_irq_trigger_u(irq, l4_utcb());
297 }
298 
299 L4_INLINE l4_msgtag_t
l4_irq_receive(l4_cap_idx_t irq,l4_timeout_t to)300 l4_irq_receive(l4_cap_idx_t irq, l4_timeout_t to) L4_NOTHROW
301 {
302   return l4_irq_receive_u(irq, to, l4_utcb());
303 }
304 
305 L4_INLINE l4_msgtag_t
l4_irq_wait(l4_cap_idx_t irq,l4_umword_t * label,l4_timeout_t to)306 l4_irq_wait(l4_cap_idx_t irq, l4_umword_t *label,
307             l4_timeout_t to) L4_NOTHROW
308 {
309   return l4_irq_wait_u(irq, label, to, l4_utcb());
310 }
311 
312 L4_INLINE l4_msgtag_t
l4_irq_unmask(l4_cap_idx_t irq)313 l4_irq_unmask(l4_cap_idx_t irq) L4_NOTHROW
314 {
315   return l4_irq_unmask_u(irq, l4_utcb());
316 }
317 
318