]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4sys/include/thread.h
update
[l4.git] / l4 / pkg / l4sys / include / thread.h
1 /**
2  * \file
3  * \brief Common thread related definitions.
4  */
5 /*
6  * (c) 2008-2009 Adam Lackorzynski <adam@os.inf.tu-dresden.de>,
7  *               Alexander Warg <warg@os.inf.tu-dresden.de>,
8  *               Björn Döbel <doebel@os.inf.tu-dresden.de>,
9  *               Torsten Frenzel <frenzel@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/types.h>
28 #include <l4/sys/utcb.h>
29 #include <l4/sys/ipc.h>
30
31 /**
32  * \defgroup l4_thread_api Thread
33  * \ingroup  l4_kernel_object_api
34  * \brief Thread object.
35  *
36  * <c>\#include <l4/sys/thread.h></c>
37  *
38  * The thread class defines a thread of execution in the L4 context.
39  * Usually user-level and kernel threads are mapped 1:1 to each other.
40  * Thread kernel objects are created using a Factory, see \ref l4_factory_api
41  * (l4_factory_create_thread()).
42  *
43  * An L4 thread encapsulates:
44  * - CPU state
45  *   - General-purpose registers
46  *   - Program counter
47  *   - Stack pointer
48  * - FPU state
49  * - Scheduling parameters
50  *   - CPU-set
51  *   - Priority (0-255)
52  *   - Time slice length
53  * - Execution state
54  *   - Blocked, Runnable, Running
55  *
56  * Thread objects provide an API for
57  * - Thread configuration and manipulation
58  * - Thread switching.
59  *
60  * The thread control functions are used to control various aspects of a
61  * thread. See l4_thread_control_start() for more information.
62  */
63
64
65 /**
66  * \brief Exchange basic thread registers.
67  * \ingroup l4_thread_api
68  *
69  * \param thread Thread to manipulate
70  * \param ip     New instruction pointer, use ~0UL to leave the
71  *               instruction pointer unchanged
72  * \param sp     New stack pointer, use ~0UL to leave the stack
73  *               pointer unchanged
74  * \param flags  Ex-regs flags, see #L4_thread_ex_regs_flags
75  *
76  * \return System call return tag
77  *
78  * This method allows to manipulate and start a thread. The basic
79  * functionality is to set the instruction pointer and the stack pointer of a
80  * thread. Additionally, this method allows also to cancel ongoing IPC
81  * operations and to force the thread to raise an artificial exception (see \a
82  * flags).
83  *
84  */
85 L4_INLINE l4_msgtag_t
86 l4_thread_ex_regs(l4_cap_idx_t thread, l4_addr_t ip, l4_addr_t sp,
87                   l4_umword_t flags) L4_NOTHROW;
88
89 /**
90  * \internal
91  * \ingroup l4_thread_api
92  */
93 L4_INLINE l4_msgtag_t
94 l4_thread_ex_regs_u(l4_cap_idx_t thread, l4_addr_t ip, l4_addr_t sp,
95                     l4_umword_t flags, l4_utcb_t *utcb) L4_NOTHROW;
96
97 /**
98  * \brief Exchange basic thread registers and return previous values.
99  * \ingroup l4_thread_api
100  *
101  * \param[in]     thread Thread to manipulate
102  * \param[in,out] ip     New instruction pointer, use ~0UL to leave the
103  *                       instruction pointer unchanged, return previous
104  *                       instruction pointer
105  * \param[in,out] sp     New stack pointer, use ~0UL to leave the stack
106  *                       pointer unchanged, returns previous stack pointer
107  * \param[in,out] flags  Ex-regs flags, see #L4_thread_ex_regs_flags, return
108  *                       previous CPU flags of the thread.
109  *
110  * \return System call return tag
111  *
112  * This method allows to manipulate and start a thread. The basic
113  * functionality is to set the instruction pointer and the stack pointer of a
114  * thread. Additionally, this method allows also to cancel ongoing IPC
115  * operations and to force the thread to raise an artificial exception (see \a
116  * flags).
117  *
118  * Returned values are valid only if function returns successfully.
119  */
120 L4_INLINE l4_msgtag_t
121 l4_thread_ex_regs_ret(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp,
122                       l4_umword_t *flags) L4_NOTHROW;
123
124 /**
125  * \internal
126  * \ingroup l4_thread_api
127  */
128 L4_INLINE l4_msgtag_t
129 l4_thread_ex_regs_ret_u(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp,
130                         l4_umword_t *flags, l4_utcb_t *utcb) L4_NOTHROW;
131
132
133
134 /**
135  * \defgroup l4_thread_control_api Thread control
136  * \ingroup l4_thread_api
137  *
138  * \brief API for Thread Control method.
139  *
140  *
141  * The thread control API provides access to almost any parameter of a thread
142  * object. The API is based on a single invocation of the thread object.
143  * However, because of the huge amount of parameters, the API provides a set
144  * of functions to set specific parameters of a thread and a commit function
145  * to commit the thread control call (see l4_thread_control_commit()).
146  *
147  * A thread control operation must always start with l4_thread_control_start()
148  * and be committed with l4_thread_control_commit().  All other thread control
149  * parameter setter functions must be called between these two functions.
150  *
151  * An example for a sequence of thread control API calls can be found below.
152  *
153  *  l4_utcb_t *u = l4_utcb(); <br>
154  *  \link l4_thread_control_start() l4_thread_control_start(u)\endlink; <br>
155  *  \link l4_thread_control_pager() l4_thread_control_pager(u, pager_cap)\endlink; <br>
156  *  \link l4_thread_control_bind() l4_thread_control_bind (u, thread_utcb, task)\endlink; <br>
157  *  \link l4_thread_control_commit() l4_thread_control_commit(u, thread_cap)\endlink; <br>
158  *
159  */
160
161 /**
162  * \brief Start a thread control API sequence.
163  * \ingroup l4_thread_control_api
164  *
165  * This function starts a sequence of thread control API functions.
166  * After this functions any of following functions may be called in any order.
167  * - l4_thread_control_pager()
168  * - l4_thread_control_exc_handler()
169  * - l4_thread_control_bind()
170  * - l4_thread_control_alien()
171  * - l4_thread_control_ux_host_syscall() (Fiasco-UX only)
172  *
173  * To commit the changes to the thread l4_thread_control_commit() must be
174  * called in the end.
175  *
176  * \note The thread control API calls store the parameters for the thread in
177  *       the UTCB of the caller, this means between l4_thread_control_start()
178  *       and l4_thread_control_commit() no functions that modify the UTCB
179  *       contents must be called.
180  */
181 L4_INLINE void
182 l4_thread_control_start(void) L4_NOTHROW;
183
184 /**
185  * \internal
186  * \ingroup l4_thread_control_api
187  */
188 L4_INLINE void
189 l4_thread_control_start_u(l4_utcb_t *utcb) L4_NOTHROW;
190
191 /**
192  * \brief Set the pager.
193  * \ingroup l4_thread_control_api
194  *
195  * \param pager     Capability selector invoked to send a page-fault IPC.
196  *
197  * \note The pager capability selector is interpreted in the task the thread
198  *       is bound to (executes in).
199  */
200 L4_INLINE void
201 l4_thread_control_pager(l4_cap_idx_t pager) L4_NOTHROW;
202
203 /**
204  * \internal
205  * \ingroup l4_thread_control_api
206  */
207 L4_INLINE void
208 l4_thread_control_pager_u(l4_cap_idx_t pager, l4_utcb_t *utcb) L4_NOTHROW;
209
210 /**
211  * \brief Set the exception handler.
212  * \ingroup l4_thread_control_api
213  *
214  * \param exc_handler  Capability selector invoked to send an exception IPC.
215  *
216  * \note The exception-handler capability selector is interpreted in the task
217  *       the thread is bound to (executes in).
218  */
219 L4_INLINE void
220 l4_thread_control_exc_handler(l4_cap_idx_t exc_handler) L4_NOTHROW;
221
222 /**
223  * \internal
224  * \ingroup l4_thread_control_api
225  */
226 L4_INLINE void
227 l4_thread_control_exc_handler_u(l4_cap_idx_t exc_handler,
228                                 l4_utcb_t *utcb) L4_NOTHROW;
229
230 /**
231  * \brief Bind the thread to a task.
232  * \ingroup l4_thread_control_api
233  *
234  * \param thread_utcb The address of the UTCB in the target task.
235  * \param task        The target task of the thread.
236  *
237  * Binding a thread to a task has the effect that the thread
238  * afterwards executes code within that task and has access to the
239  * resources visible within that task.
240  *
241  * \note There should not be more than one thread use a UTCB to prevent
242  *       data corruption.
243  *
244  */
245 L4_INLINE void
246 l4_thread_control_bind(l4_utcb_t *thread_utcb,
247                        l4_cap_idx_t task) L4_NOTHROW;
248
249 /**
250  * \internal
251  * \ingroup l4_thread_control_api
252  */
253 L4_INLINE void
254 l4_thread_control_bind_u(l4_utcb_t *thread_utcb,
255                          l4_cap_idx_t task, l4_utcb_t *utcb) L4_NOTHROW;
256
257 /**
258  * \brief Enable alien mode.
259  * \ingroup l4_thread_control_api
260  * \param   on    Boolean value defining the state of the feature.
261  *
262  * Alien mode means the thread is not allowed to invoke L4 kernel objects
263  * directly and it is also not allowed to allocate FPU state. All those
264  * operations result in an exception IPC that gets sent through the pager
265  * capability. The responsible pager can then selectively allow an object
266  * invocation or allocate FPU state for the thread.
267  *
268  * This feature can be used to attach a debugger to a thread and trace all
269  * object invocations.
270  */
271 L4_INLINE void
272 l4_thread_control_alien(int on) L4_NOTHROW;
273
274 /**
275  * \internal
276  * \ingroup l4_thread_control_api
277  */
278 L4_INLINE void
279 l4_thread_control_alien_u(l4_utcb_t *utcb, int on) L4_NOTHROW;
280
281 /**
282  * \brief Enable pass through of native host (Linux) system calls.
283  * \ingroup l4_thread_control_api
284  * \param   on    Boolean value defining the state of the feature.
285  *
286  * \pre Running on Fiasco-UX
287  *
288  * This enables the thread to do host system calls. This feature is only
289  * available in Fiasco-UX and ignored in other environments.
290  */
291 L4_INLINE void
292 l4_thread_control_ux_host_syscall(int on) L4_NOTHROW;
293
294 /**
295  * \internal
296  * \ingroup l4_thread_control_api
297  */
298 L4_INLINE void
299 l4_thread_control_ux_host_syscall_u(l4_utcb_t *utcb, int on) L4_NOTHROW;
300
301
302
303 /**
304  * \brief Commit the thread control parameters.
305  * \ingroup l4_thread_control_api
306  *
307  * \param thread  Capability selector of target thread to commit to.
308  * \return system call return tag
309  */
310 L4_INLINE l4_msgtag_t
311 l4_thread_control_commit(l4_cap_idx_t thread) L4_NOTHROW;
312
313 /**
314  * \internal
315  * \ingroup l4_thread_control_api
316  */
317 L4_INLINE l4_msgtag_t
318 l4_thread_control_commit_u(l4_cap_idx_t thread, l4_utcb_t *utcb) L4_NOTHROW;
319
320 /**
321  * \brief Yield current time slice.
322  * \ingroup l4_thread_api
323  *
324  * \return system call return tag
325  */
326 L4_INLINE l4_msgtag_t
327 l4_thread_yield(void) L4_NOTHROW;
328
329 /**
330  * \brief Switch to another thread (and donate the remaining time slice).
331  * \ingroup l4_thread_api
332  *
333  * \param to_thread   The thread to switch to.
334  *
335  * \return system call return tag
336  */
337 L4_INLINE l4_msgtag_t
338 l4_thread_switch(l4_cap_idx_t to_thread) L4_NOTHROW;
339
340 /**
341  * \internal
342  * \ingroup l4_thread_api
343  */
344 L4_INLINE l4_msgtag_t
345 l4_thread_switch_u(l4_cap_idx_t to_thread, l4_utcb_t *utcb) L4_NOTHROW;
346
347
348
349 /**
350  * \brief Get consumed timed of thread in µs.
351  * \ingroup l4_thread_api
352  * \param thread Thread to get the consumed time from.
353  *
354  * The consumed time is returned as l4_kernel_clock_t at UTCB message
355  * register 0.
356  */
357 L4_INLINE l4_msgtag_t
358 l4_thread_stats_time(l4_cap_idx_t thread) L4_NOTHROW;
359
360 /**
361  * \internal
362  * \ingroup l4_thread_api
363  */
364 L4_INLINE l4_msgtag_t
365 l4_thread_stats_time_u(l4_cap_idx_t thread, l4_utcb_t *utcb) L4_NOTHROW;
366
367
368 /**
369  * \brief vCPU return from event handler.
370  * \ingroup l4_thread_api
371  *
372  * \return Message tag to be used for l4_sndfpage_add() and
373  *         l4_thread_vcpu_commit()
374  *
375  * The vCPU resume functionality is split in multiple functions to allow the
376  * specification of additional send-flex-pages using l4_sndfpage_add().
377  */
378 L4_INLINE l4_msgtag_t
379 l4_thread_vcpu_resume_start(void) L4_NOTHROW;
380
381 /**
382  * \internal
383  * \ingroup l4_thread_api
384  */
385 L4_INLINE l4_msgtag_t
386 l4_thread_vcpu_resume_start_u(l4_utcb_t *utcb) L4_NOTHROW;
387
388 /**
389  * \brief Commit vCPU resume.
390  * \ingroup l4_thread_api
391  *
392  * \param thread    Thread to be resumed, the invalid cap can be used
393  *                  for the current thread.
394  * \param tag       Tag to use, returned by l4_thread_vcpu_resume_start()
395  *
396  * \return System call result message tag. In extended vCPU mode and when
397  * the virtual interrupts are cleared, the return code 1 flags an incoming
398  * IPC message, whereas 0 indicates a VM exit. An error are returned upon:
399  *   - Insufficient rights on the given task capability (-L4_EPERM).
400  *   - Given task capability is invalid (-L4_ENOENT).
401  *   - A supplied mapping failed.
402  *
403  * To resume into another address space the capability to the target task
404  * must be set in the vCPU-state, with all lower bits in the task
405  * capability cleared. The kernel adds the #L4_SYSF_SEND flag to this field
406  * to indicate that the capability has been referenced in the kernel.
407  * Consecutive resumes will not reference the task capability again until
408  * all bits are cleared again. To release a task use the different task
409  * capability or use an invalid capability with the #L4_SYSF_REPLY flag set.
410  *
411  * \see l4_vcpu_state_t
412  */
413 L4_INLINE l4_msgtag_t
414 l4_thread_vcpu_resume_commit(l4_cap_idx_t thread,
415                              l4_msgtag_t tag) L4_NOTHROW;
416
417 /**
418  * \internal
419  * \ingroup l4_thread_api
420  */
421 L4_INLINE l4_msgtag_t
422 l4_thread_vcpu_resume_commit_u(l4_cap_idx_t thread,
423                                l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW;
424
425
426 /**
427  * \brief Enable or disable the vCPU feature for the thread.
428  * \ingroup l4_thread_api
429  *
430  * \param thread The thread for which the vCPU feature shall be enabled or
431  *               disabled.
432  * \param vcpu_state The virtual address where the kernel shall store the vCPU
433  *                   state in case of vCPU exits. The address must be a valid
434  *                   kernel-user-memory address.
435  * \return Systemcall result message tag.
436  *
437  * This function enables the vCPU feature of the \a thread if \a vcpu_state
438  * is set to a valid kernel-user-memory address, or disables the vCPU feature
439  * if \a vcpu_state is 0.
440  *
441  */
442 L4_INLINE l4_msgtag_t
443 l4_thread_vcpu_control(l4_cap_idx_t thread, l4_addr_t vcpu_state) L4_NOTHROW;
444
445 /**
446  * \internal
447  * \ingroup l4_thread_api
448  */
449 L4_INLINE l4_msgtag_t
450 l4_thread_vcpu_control_u(l4_cap_idx_t thread, l4_addr_t vcpu_state,
451                          l4_utcb_t *utcb) L4_NOTHROW;
452
453 /**
454  * \brief Enable or disable the extended vCPU feature for the thread.
455  * \ingroup l4_thread_api
456  *
457  * \param thread The thread for which the extended vCPU feature shall be
458  *               enabled or disabled.
459  * \param vcpu_state The virtual address where the kernel shall store the vCPU
460  *                   state in case of vCPU exits. The address must be a valid
461  *                   kernel-user-memory address.
462  * \return Systemcall result message tag.
463  *
464  * The extended vCPU feature allows the use of hardware-virtualization
465  * features such as Intel's VT or AMD's SVM.
466  *
467  * This function enables the extended vCPU feature of the \a thread
468  * if \a vcpu_state is set to a valid kernel-user-memory address, or disables
469  * the vCPU feature if \a vcpu_state is 0.
470  *
471  */
472 L4_INLINE l4_msgtag_t
473 l4_thread_vcpu_control_ext(l4_cap_idx_t thread, l4_addr_t ext_vcpu_state) L4_NOTHROW;
474
475 /**
476  * \internal
477  * \ingroup l4_thread_api
478  */
479 L4_INLINE l4_msgtag_t
480 l4_thread_vcpu_control_ext_u(l4_cap_idx_t thread, l4_addr_t ext_vcpu_state,
481                              l4_utcb_t *utcb) L4_NOTHROW;
482
483
484 /**
485  * \brief Register an IRQ that will trigger upon deletion events.
486  * \ingroup l4_thread_api
487  *
488  * \param thread    Thread to register IRQ for.
489  * \param irq       Irq to register.
490  *
491  * \return System call result message tag.
492  */
493 L4_INLINE l4_msgtag_t
494 l4_thread_register_del_irq(l4_cap_idx_t thread, l4_cap_idx_t irq) L4_NOTHROW;
495
496 /**
497  * \internal
498  * \ingroup l4_thread_api
499  */
500 L4_INLINE l4_msgtag_t
501 l4_thread_register_del_irq_u(l4_cap_idx_t thread, l4_cap_idx_t irq,
502                              l4_utcb_t *utcb) L4_NOTHROW;
503
504 /**
505  * \brief Start a thread sender modifiction sequence.
506  * \ingroup l4_thread_api
507  *
508  * Add modification rules with l4_thread_modify_sender_add() and commit with
509  * l4_thread_modify_sender_commit(). Do not touch the UTCB between
510  * l4_thread_modify_sender_start() and l4_thread_modify_sender_commit().
511  *
512  * \see l4_thread_modify_sender_add
513  * \see l4_thread_modify_sender_commit
514  */
515 L4_INLINE l4_msgtag_t
516 l4_thread_modify_sender_start(void) L4_NOTHROW;
517
518 /**
519  * \internal
520  * \ingroup l4_thread_api
521  */
522 L4_INLINE l4_msgtag_t
523 l4_thread_modify_sender_start_u(l4_utcb_t *u) L4_NOTHROW;
524
525 /**
526  * \brief Add a modification pattern to a sender modification sequence.
527  * \ingroup l4_thread_api
528  *
529  * \param tag        Tag received from l4_thread_modify_sender_start() or
530  *                   previous l4_thread_modify_sender_add() calls from
531  *                   the same sequence.
532  * \param match_mask Bitmask of bits to match the label.
533  * \param match      Bitmask that must be equal to the label after applying
534  *                   match_mask.
535  * \param del_bits   Bits to be deleted from the label.
536  * \param add_bits   Bits to be added to the label.
537  *
538  * \return 0 on sucess, <0 on error
539  *
540  * In pseudo code:
541  *   if ((sender_label & match_mask) == match)
542  *     { label = (label & ~del_bits) | add_bits; }
543  *
544  * Only the first match is applied.
545  *
546  * \see l4_thread_modify_sender_start
547  * \see l4_thread_modify_sender_commit
548  */
549 L4_INLINE int
550 l4_thread_modify_sender_add(l4_umword_t match_mask,
551                             l4_umword_t match,
552                             l4_umword_t del_bits,
553                             l4_umword_t add_bits,
554                             l4_msgtag_t *tag) L4_NOTHROW;
555
556 /**
557  * \internal
558  * \ingroup l4_thread_api
559  */
560 L4_INLINE int
561 l4_thread_modify_sender_add_u(l4_umword_t match_mask,
562                               l4_umword_t match,
563                               l4_umword_t del_bits,
564                               l4_umword_t add_bits,
565                               l4_msgtag_t *tag, l4_utcb_t *u) L4_NOTHROW;
566
567 /**
568  * \brief Apply (commit) a sender modification sequence.
569  * \ingroup l4_thread_api
570  *
571  * \see l4_thread_modify_sender_start
572  * \see l4_thread_modify_sender_add
573  */
574 L4_INLINE l4_msgtag_t
575 l4_thread_modify_sender_commit(l4_cap_idx_t thread, l4_msgtag_t tag) L4_NOTHROW;
576
577 /**
578  * \internal
579  * \ingroup l4_thread_api
580  */
581 L4_INLINE l4_msgtag_t
582 l4_thread_modify_sender_commit_u(l4_cap_idx_t thread, l4_msgtag_t tag,
583                                  l4_utcb_t *u) L4_NOTHROW;
584
585 /**
586  * \brief Operations on thread objects.
587  * \ingroup l4_thread_api
588  * \hideinitializer
589  * \internal
590  */
591 enum L4_thread_ops
592 {
593   L4_THREAD_CONTROL_OP                = 0UL,    /**< Control operation */
594   L4_THREAD_EX_REGS_OP                = 1UL,    /**< Exchange registers operation */
595   L4_THREAD_SWITCH_OP                 = 2UL,    /**< Do a thread switch */
596   L4_THREAD_STATS_OP                  = 3UL,    /**< Thread statistics */
597   L4_THREAD_VCPU_RESUME_OP            = 4UL,    /**< VCPU resume */
598   L4_THREAD_REGISTER_DELETE_IRQ_OP    = 5UL,    /**< Register an IPC-gate deletion IRQ */
599   L4_THREAD_MODIFY_SENDER_OP          = 6UL,    /**< Modify all senders IDs that match the given pattern */
600   L4_THREAD_VCPU_CONTROL_OP           = 7UL,    /**< Enable / disable VCPU feature */
601   L4_THREAD_VCPU_CONTROL_EXT_OP       = L4_THREAD_VCPU_CONTROL_OP | 0x10000,
602   L4_THREAD_X86_GDT_OP                = 0x10UL, /**< Gdt */
603   L4_THREAD_ARM_TPIDRURO_OP           = 0x10UL, /**< Set TPIDRURO register */
604   L4_THREAD_AMD64_SET_SEGMENT_BASE_OP = 0x12UL, /**< Set segment base */
605   L4_THREAD_OPCODE_MASK               = 0xffff, /**< Mask for opcodes */
606 };
607
608 /**
609  * \brief Flags for the thread control operation.
610  * \ingroup l4_thread_api
611  * \hideinitializer
612  * \internal
613  *
614  * Values for the enabled flags need to be given in their appropriate field
615  * in the UTCB,
616  * \see l4_thread_control
617  */
618 enum L4_thread_control_flags
619 {
620   /** The pager will be given. */
621   L4_THREAD_CONTROL_SET_PAGER       = 0x0010000,
622   /** The task to bind the thread to will be given. */
623   L4_THREAD_CONTROL_BIND_TASK       = 0x0200000,
624   /** Alien state of the thread is set. */
625   L4_THREAD_CONTROL_ALIEN           = 0x0400000,
626   /** Fiasco-UX only: pass-through of host system calls is set. */
627   L4_THREAD_CONTROL_UX_NATIVE       = 0x0800000,
628   /** The exception handler of the thread will be given. */
629   L4_THREAD_CONTROL_SET_EXC_HANDLER = 0x1000000,
630 };
631
632 /**
633  * \brief Indices for the values in the message register for thread control.
634  * \ingroup l4_thread_api
635  * \hideinitializer
636  * \internal
637  *
638  * The values indicate the index in the message registers during
639  * thread-control operation.
640  */
641 enum L4_thread_control_mr_indices
642 {
643   L4_THREAD_CONTROL_MR_IDX_FLAGS       = 0, /**< \see #L4_thread_control_flags. */
644   L4_THREAD_CONTROL_MR_IDX_PAGER       = 1, /**< Index for pager cap */
645   L4_THREAD_CONTROL_MR_IDX_EXC_HANDLER = 2, /**< Index for exception handler */
646   L4_THREAD_CONTROL_MR_IDX_FLAG_VALS   = 4, /**< Index for feature values */
647   L4_THREAD_CONTROL_MR_IDX_BIND_UTCB   = 5, /**< Index for UTCB address for bind */
648   L4_THREAD_CONTROL_MR_IDX_BIND_TASK   = 6, /**< Index for task flex-page for bind */
649 };
650
651 /**
652  * \brief Flags for the thread ex-regs operation.
653  * \ingroup l4_thread_api
654  * \hideinitializer
655  */
656 enum L4_thread_ex_regs_flags
657 {
658   L4_THREAD_EX_REGS_CANCEL            = 0x10000UL, /**< Cancel ongoing IPC in the thread. */
659   L4_THREAD_EX_REGS_TRIGGER_EXCEPTION = 0x20000UL, /**< Trigger artificial exception in thread. */
660 };
661
662
663 /* IMPLEMENTATION -----------------------------------------------------------*/
664
665 #include <l4/sys/ipc.h>
666 #include <l4/sys/types.h>
667
668 L4_INLINE l4_msgtag_t
669 l4_thread_ex_regs_u(l4_cap_idx_t thread, l4_addr_t ip, l4_addr_t sp,
670                     l4_umword_t flags, l4_utcb_t *utcb) L4_NOTHROW
671 {
672   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
673   v->mr[0] = L4_THREAD_EX_REGS_OP | flags;
674   v->mr[1] = ip;
675   v->mr[2] = sp;
676   return l4_ipc_call(thread, utcb, l4_msgtag(L4_PROTO_THREAD, 3, 0, 0), L4_IPC_NEVER);
677 }
678
679 L4_INLINE l4_msgtag_t
680 l4_thread_ex_regs_ret_u(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp,
681                         l4_umword_t *flags, l4_utcb_t *utcb) L4_NOTHROW
682 {
683   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
684   l4_msgtag_t ret = l4_thread_ex_regs_u(thread, *ip, *sp, *flags, utcb);
685   if (l4_error_u(ret, utcb))
686     return ret;
687
688   *flags = v->mr[0];
689   *ip    = v->mr[1];
690   *sp    = v->mr[2];
691   return ret;
692 }
693
694 L4_INLINE void
695 l4_thread_control_start_u(l4_utcb_t *utcb) L4_NOTHROW
696 {
697   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
698   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS] = L4_THREAD_CONTROL_OP;
699 }
700
701 L4_INLINE void
702 l4_thread_control_pager_u(l4_cap_idx_t pager, l4_utcb_t *utcb) L4_NOTHROW
703 {
704   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
705   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS] |= L4_THREAD_CONTROL_SET_PAGER;
706   v->mr[L4_THREAD_CONTROL_MR_IDX_PAGER]  = pager;
707 }
708
709 L4_INLINE void
710 l4_thread_control_exc_handler_u(l4_cap_idx_t exc_handler,
711                                 l4_utcb_t *utcb) L4_NOTHROW
712 {
713   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
714   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS]       |= L4_THREAD_CONTROL_SET_EXC_HANDLER;
715   v->mr[L4_THREAD_CONTROL_MR_IDX_EXC_HANDLER]  = exc_handler;
716 }
717
718 L4_INLINE void
719 l4_thread_control_bind_u(l4_utcb_t *thread_utcb, l4_cap_idx_t task,
720                          l4_utcb_t *utcb) L4_NOTHROW
721 {
722   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
723   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS]         |= L4_THREAD_CONTROL_BIND_TASK;
724   v->mr[L4_THREAD_CONTROL_MR_IDX_BIND_UTCB]      = (l4_addr_t)thread_utcb;
725   v->mr[L4_THREAD_CONTROL_MR_IDX_BIND_TASK]      = L4_ITEM_MAP;
726   v->mr[L4_THREAD_CONTROL_MR_IDX_BIND_TASK + 1]  = l4_obj_fpage(task, 0, L4_FPAGE_RWX).raw;
727 }
728
729 L4_INLINE void
730 l4_thread_control_alien_u(l4_utcb_t *utcb, int on) L4_NOTHROW
731 {
732   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
733   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS]     |= L4_THREAD_CONTROL_ALIEN;
734   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAG_VALS] |= on ? L4_THREAD_CONTROL_ALIEN : 0;
735 }
736
737 L4_INLINE void
738 l4_thread_control_ux_host_syscall_u(l4_utcb_t *utcb, int on) L4_NOTHROW
739 {
740   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
741   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS]     |= L4_THREAD_CONTROL_UX_NATIVE;
742   v->mr[L4_THREAD_CONTROL_MR_IDX_FLAG_VALS] |= on ? L4_THREAD_CONTROL_UX_NATIVE : 0;
743 }
744
745 L4_INLINE l4_msgtag_t
746 l4_thread_control_commit_u(l4_cap_idx_t thread, l4_utcb_t *utcb) L4_NOTHROW
747 {
748   int items = 0;
749   if (l4_utcb_mr_u(utcb)->mr[L4_THREAD_CONTROL_MR_IDX_FLAGS] & L4_THREAD_CONTROL_BIND_TASK)
750     items = 1;
751   return l4_ipc_call(thread, utcb, l4_msgtag(L4_PROTO_THREAD, 6, items, 0), L4_IPC_NEVER);
752 }
753
754
755 L4_INLINE l4_msgtag_t
756 l4_thread_yield(void) L4_NOTHROW
757 {
758   l4_ipc_receive(L4_INVALID_CAP, NULL, L4_IPC_BOTH_TIMEOUT_0);
759   return l4_msgtag(0, 0, 0, 0);
760 }
761
762 /* Preliminary, to be changed */
763 L4_INLINE l4_msgtag_t
764 l4_thread_switch_u(l4_cap_idx_t to_thread, l4_utcb_t *utcb) L4_NOTHROW
765 {
766   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
767   v->mr[0] = L4_THREAD_SWITCH_OP;
768   return l4_ipc_call(to_thread, utcb, l4_msgtag(L4_PROTO_THREAD, 1, 0, 0), L4_IPC_NEVER);
769 }
770
771
772 L4_INLINE l4_msgtag_t
773 l4_thread_stats_time_u(l4_cap_idx_t thread, l4_utcb_t *utcb) L4_NOTHROW
774 {
775   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
776   v->mr[0] = L4_THREAD_STATS_OP;
777   return l4_ipc_call(thread, utcb, l4_msgtag(L4_PROTO_THREAD, 1, 0, 0), L4_IPC_NEVER);
778 }
779
780 L4_INLINE l4_msgtag_t
781 l4_thread_vcpu_resume_start_u(l4_utcb_t *utcb) L4_NOTHROW
782 {
783   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
784   v->mr[0] = L4_THREAD_VCPU_RESUME_OP;
785   return l4_msgtag(L4_PROTO_THREAD, 1, 0, 0);
786 }
787
788 L4_INLINE l4_msgtag_t
789 l4_thread_vcpu_resume_commit_u(l4_cap_idx_t thread,
790                                l4_msgtag_t tag, l4_utcb_t *utcb) L4_NOTHROW
791 {
792   return l4_ipc_call(thread, utcb, tag, L4_IPC_NEVER);
793 }
794
795 L4_INLINE l4_msgtag_t
796 l4_thread_ex_regs(l4_cap_idx_t thread, l4_addr_t ip, l4_addr_t sp,
797                     l4_umword_t flags) L4_NOTHROW
798 {
799   return l4_thread_ex_regs_u(thread, ip, sp, flags, l4_utcb());
800 }
801
802 L4_INLINE l4_msgtag_t
803 l4_thread_ex_regs_ret(l4_cap_idx_t thread, l4_addr_t *ip, l4_addr_t *sp,
804                       l4_umword_t *flags) L4_NOTHROW
805 {
806   return l4_thread_ex_regs_ret_u(thread, ip, sp, flags, l4_utcb());
807 }
808
809 L4_INLINE void
810 l4_thread_control_start(void) L4_NOTHROW
811 {
812   l4_thread_control_start_u(l4_utcb());
813 }
814
815 L4_INLINE void
816 l4_thread_control_pager(l4_cap_idx_t pager) L4_NOTHROW
817 {
818   l4_thread_control_pager_u(pager, l4_utcb());
819 }
820
821 L4_INLINE void
822 l4_thread_control_exc_handler(l4_cap_idx_t exc_handler) L4_NOTHROW
823 {
824   l4_thread_control_exc_handler_u(exc_handler, l4_utcb());
825 }
826
827
828 L4_INLINE void
829 l4_thread_control_bind(l4_utcb_t *thread_utcb, l4_cap_idx_t task) L4_NOTHROW
830 {
831   l4_thread_control_bind_u(thread_utcb, task, l4_utcb());
832 }
833
834 L4_INLINE void
835 l4_thread_control_alien(int on) L4_NOTHROW
836 {
837   l4_thread_control_alien_u(l4_utcb(), on);
838 }
839
840 L4_INLINE void
841 l4_thread_control_ux_host_syscall(int on) L4_NOTHROW
842 {
843   l4_thread_control_ux_host_syscall_u(l4_utcb(), on);
844 }
845
846 L4_INLINE l4_msgtag_t
847 l4_thread_control_commit(l4_cap_idx_t thread) L4_NOTHROW
848 {
849   return l4_thread_control_commit_u(thread, l4_utcb());
850 }
851
852
853
854
855 L4_INLINE l4_msgtag_t
856 l4_thread_switch(l4_cap_idx_t to_thread) L4_NOTHROW
857 {
858   return l4_thread_switch_u(to_thread, l4_utcb());
859 }
860
861
862
863
864 L4_INLINE l4_msgtag_t
865 l4_thread_stats_time(l4_cap_idx_t thread) L4_NOTHROW
866 {
867   return l4_thread_stats_time_u(thread, l4_utcb());
868 }
869
870 L4_INLINE l4_msgtag_t
871 l4_thread_vcpu_resume_start(void) L4_NOTHROW
872 {
873   return l4_thread_vcpu_resume_start_u(l4_utcb());
874 }
875
876 L4_INLINE l4_msgtag_t
877 l4_thread_vcpu_resume_commit(l4_cap_idx_t thread,
878                              l4_msgtag_t tag) L4_NOTHROW
879 {
880   return l4_thread_vcpu_resume_commit_u(thread, tag, l4_utcb());
881 }
882
883
884 L4_INLINE l4_msgtag_t
885 l4_thread_register_del_irq_u(l4_cap_idx_t thread, l4_cap_idx_t irq,
886                              l4_utcb_t *u) L4_NOTHROW
887 {
888   l4_msg_regs_t *m = l4_utcb_mr_u(u);
889   m->mr[0] = L4_THREAD_REGISTER_DELETE_IRQ_OP;
890   m->mr[1] = l4_map_obj_control(0,0);
891   m->mr[2] = l4_obj_fpage(irq, 0, L4_CAP_FPAGE_RWS).raw;
892   return l4_ipc_call(thread, u, l4_msgtag(L4_PROTO_THREAD, 1, 1, 0), L4_IPC_NEVER);
893
894 }
895
896 L4_INLINE l4_msgtag_t
897 l4_thread_register_del_irq(l4_cap_idx_t thread, l4_cap_idx_t irq) L4_NOTHROW
898 {
899   return l4_thread_register_del_irq_u(thread, irq, l4_utcb());
900 }
901
902
903 L4_INLINE l4_msgtag_t
904 l4_thread_vcpu_control_u(l4_cap_idx_t thread, l4_addr_t vcpu_state,
905                          l4_utcb_t *utcb) L4_NOTHROW
906 {
907   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
908   v->mr[0] = L4_THREAD_VCPU_CONTROL_OP;
909   v->mr[1] = vcpu_state;
910   return l4_ipc_call(thread, utcb, l4_msgtag(L4_PROTO_THREAD, 2, 0, 0), L4_IPC_NEVER);
911 }
912
913 L4_INLINE l4_msgtag_t
914 l4_thread_vcpu_control(l4_cap_idx_t thread, l4_addr_t vcpu_state) L4_NOTHROW
915 { return l4_thread_vcpu_control_u(thread, vcpu_state, l4_utcb()); }
916
917
918 L4_INLINE l4_msgtag_t
919 l4_thread_vcpu_control_ext_u(l4_cap_idx_t thread, l4_addr_t ext_vcpu_state,
920                              l4_utcb_t *utcb) L4_NOTHROW
921 {
922   l4_msg_regs_t *v = l4_utcb_mr_u(utcb);
923   v->mr[0] = L4_THREAD_VCPU_CONTROL_EXT_OP;
924   v->mr[1] = ext_vcpu_state;
925   return l4_ipc_call(thread, utcb, l4_msgtag(L4_PROTO_THREAD, 2, 0, 0), L4_IPC_NEVER);
926 }
927
928 L4_INLINE l4_msgtag_t
929 l4_thread_vcpu_control_ext(l4_cap_idx_t thread, l4_addr_t ext_vcpu_state) L4_NOTHROW
930 { return l4_thread_vcpu_control_ext_u(thread, ext_vcpu_state, l4_utcb()); }
931
932 L4_INLINE l4_msgtag_t
933 l4_thread_modify_sender_start_u(l4_utcb_t *u) L4_NOTHROW
934 {
935   l4_msg_regs_t *m = l4_utcb_mr_u(u);
936   m->mr[0] = L4_THREAD_MODIFY_SENDER_OP;
937   return l4_msgtag(L4_PROTO_THREAD, 1, 0, 0);
938 }
939
940 L4_INLINE int
941 l4_thread_modify_sender_add_u(l4_umword_t match_mask,
942                               l4_umword_t match,
943                               l4_umword_t del_bits,
944                               l4_umword_t add_bits,
945                               l4_msgtag_t *tag, l4_utcb_t *u) L4_NOTHROW
946 {
947   l4_msg_regs_t *m = l4_utcb_mr_u(u);
948   unsigned w = l4_msgtag_words(*tag);
949   if (w >= L4_UTCB_GENERIC_DATA_SIZE - 4)
950     return -L4_ENOMEM;
951
952   m->mr[w]   = match_mask;
953   m->mr[w+1] = match;
954   m->mr[w+2] = del_bits;
955   m->mr[w+3] = add_bits;
956
957   *tag = l4_msgtag(l4_msgtag_label(*tag), w + 4, 0, 0);
958
959   return 0;
960 }
961
962 L4_INLINE l4_msgtag_t
963 l4_thread_modify_sender_commit_u(l4_cap_idx_t thread, l4_msgtag_t tag,
964                                  l4_utcb_t *u) L4_NOTHROW
965 {
966   return l4_ipc_call(thread, u, tag, L4_IPC_NEVER);
967 }
968
969 L4_INLINE l4_msgtag_t
970 l4_thread_modify_sender_start(void) L4_NOTHROW
971 {
972   return l4_thread_modify_sender_start_u(l4_utcb());
973 }
974
975 L4_INLINE int
976 l4_thread_modify_sender_add(l4_umword_t match_mask,
977                             l4_umword_t match,
978                             l4_umword_t del_bits,
979                             l4_umword_t add_bits,
980                             l4_msgtag_t *tag) L4_NOTHROW
981 {
982   return l4_thread_modify_sender_add_u(match_mask, match,
983                                        del_bits, add_bits, tag, l4_utcb());
984 }
985
986 L4_INLINE l4_msgtag_t
987 l4_thread_modify_sender_commit(l4_cap_idx_t thread, l4_msgtag_t tag) L4_NOTHROW
988 {
989   return l4_thread_modify_sender_commit_u(thread, tag, l4_utcb());
990 }