1/*
2 * Copyright 2014, General Dynamics C4 Systems
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 */
6
7#pragma once
8
9#include <types.h>
10#include <api/failures.h>
11#include <object/structures.h>
12
13#include <machine/registerset.h>
14#include <object/cnode.h>
15
16#ifdef CONFIG_DEBUG_BUILD
17/* Maximum length of the tcb name, including null terminator */
18#define TCB_NAME_LENGTH (BIT(seL4_TCBBits-1) - (tcbCNodeEntries * sizeof(cte_t)) - sizeof(debug_tcb_t))
19compile_assert(tcb_name_fits, TCB_NAME_LENGTH > 0)
20#endif
21
22struct tcb_queue {
23    tcb_t *head;
24    tcb_t *end;
25};
26typedef struct tcb_queue tcb_queue_t;
27
28static inline unsigned int setMR(tcb_t *receiver, word_t *receiveIPCBuffer,
29                                 unsigned int offset, word_t reg)
30{
31    if (offset >= n_msgRegisters) {
32        if (receiveIPCBuffer) {
33            receiveIPCBuffer[offset + 1] = reg;
34            return offset + 1;
35        } else {
36            return n_msgRegisters;
37        }
38    } else {
39        setRegister(receiver, msgRegisters[offset], reg);
40        return offset + 1;
41    }
42}
43
44void tcbSchedEnqueue(tcb_t *tcb);
45void tcbSchedAppend(tcb_t *tcb);
46void tcbSchedDequeue(tcb_t *tcb);
47
48#ifdef CONFIG_DEBUG_BUILD
49void tcbDebugAppend(tcb_t *tcb);
50void tcbDebugRemove(tcb_t *tcb);
51#endif
52#ifdef CONFIG_KERNEL_MCS
53void tcbReleaseRemove(tcb_t *tcb);
54void tcbReleaseEnqueue(tcb_t *tcb);
55tcb_t *tcbReleaseDequeue(void);
56#endif
57
58#ifdef ENABLE_SMP_SUPPORT
59void remoteQueueUpdate(tcb_t *tcb);
60void remoteTCBStall(tcb_t *tcb);
61
62#define SCHED_ENQUEUE(_t) do {      \
63    tcbSchedEnqueue(_t);            \
64    remoteQueueUpdate(_t);          \
65} while (0)
66
67#define SCHED_APPEND(_t) do {       \
68    tcbSchedAppend(_t);             \
69    remoteQueueUpdate(_t);          \
70} while (0)
71
72#else
73#define SCHED_ENQUEUE(_t)           tcbSchedEnqueue(_t)
74#define SCHED_APPEND(_t)            tcbSchedAppend(_t)
75#endif /* ENABLE_SMP_SUPPORT */
76
77#define SCHED_ENQUEUE_CURRENT_TCB   tcbSchedEnqueue(NODE_STATE(ksCurThread))
78#define SCHED_APPEND_CURRENT_TCB    tcbSchedAppend(NODE_STATE(ksCurThread))
79
80#ifdef CONFIG_KERNEL_MCS
81/* Add TCB into the priority ordered endpoint queue */
82static inline tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue)
83{
84    /* start at the back of the queue as FIFO is the common case */
85    tcb_t *before = queue.end;
86    tcb_t *after = NULL;
87
88    /* find a place to put the tcb */
89    while (unlikely(before != NULL && tcb->tcbPriority > before->tcbPriority)) {
90        after = before;
91        before = after->tcbEPPrev;
92    }
93
94    if (unlikely(before == NULL)) {
95        /* insert at head */
96        queue.head = tcb;
97    } else {
98        before->tcbEPNext = tcb;
99    }
100
101    if (likely(after == NULL)) {
102        /* insert at tail */
103        queue.end = tcb;
104    } else {
105        after->tcbEPPrev = tcb;
106    }
107
108    tcb->tcbEPNext = after;
109    tcb->tcbEPPrev = before;
110
111    return queue;
112}
113
114tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
115
116#else
117tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue);
118tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
119
120void setupCallerCap(tcb_t *sender, tcb_t *receiver, bool_t canGrant);
121void deleteCallerCap(tcb_t *receiver);
122#endif
123
124word_t copyMRs(tcb_t *sender, word_t *sendBuf, tcb_t *receiver,
125               word_t *recvBuf, word_t n);
126exception_t decodeTCBInvocation(word_t invLabel, word_t length, cap_t cap,
127                                cte_t *slot, extra_caps_t excaps, bool_t call,
128                                word_t *buffer);
129exception_t decodeCopyRegisters(cap_t cap, word_t length,
130                                extra_caps_t excaps, word_t *buffer);
131exception_t decodeReadRegisters(cap_t cap, word_t length, bool_t call,
132                                word_t *buffer);
133exception_t decodeWriteRegisters(cap_t cap, word_t length, word_t *buffer);
134exception_t decodeTCBConfigure(cap_t cap, word_t length,
135                               cte_t *slot, extra_caps_t rootCaps, word_t *buffer);
136exception_t decodeSetPriority(cap_t cap, word_t length, extra_caps_t excaps, word_t *buffer);
137exception_t decodeSetMCPriority(cap_t cap, word_t length, extra_caps_t excaps, word_t *buffer);
138#ifdef CONFIG_KERNEL_MCS
139exception_t decodeSetSchedParams(cap_t cap, word_t length, cte_t *slot, extra_caps_t excaps, word_t *buffer);
140#else
141exception_t decodeSetSchedParams(cap_t cap, word_t length, extra_caps_t excaps, word_t *buffer);
142#endif
143exception_t decodeSetIPCBuffer(cap_t cap, word_t length,
144                               cte_t *slot, extra_caps_t excaps, word_t *buffer);
145exception_t decodeSetSpace(cap_t cap, word_t length,
146                           cte_t *slot, extra_caps_t excaps, word_t *buffer);
147exception_t decodeDomainInvocation(word_t invLabel, word_t length,
148                                   extra_caps_t excaps, word_t *buffer);
149exception_t decodeBindNotification(cap_t cap, extra_caps_t excaps);
150exception_t decodeUnbindNotification(cap_t cap);
151#ifdef CONFIG_KERNEL_MCS
152exception_t decodeSetTimeoutEndpoint(cap_t cap, cte_t *slot, extra_caps_t excaps);
153#endif
154
155
156#ifdef CONFIG_KERNEL_MCS
157enum thread_control_caps_flag {
158    thread_control_caps_update_ipc_buffer = 0x1,
159    thread_control_caps_update_space = 0x2,
160    thread_control_caps_update_fault = 0x4,
161    thread_control_caps_update_timeout = 0x8,
162};
163
164enum thread_control_sched_flag {
165    thread_control_sched_update_priority = 0x1,
166    thread_control_sched_update_mcp = 0x2,
167    thread_control_sched_update_sc = 0x4,
168    thread_control_sched_update_fault = 0x8,
169};
170#else
171enum thread_control_flag {
172    thread_control_update_priority = 0x1,
173    thread_control_update_ipc_buffer = 0x2,
174    thread_control_update_space = 0x4,
175    thread_control_update_mcp = 0x8,
176#ifdef CONFIG_KERNEL_MCS
177    thread_control_update_sc = 0x10,
178    thread_control_update_fault = 0x20,
179    thread_control_update_timeout = 0x40,
180#endif
181};
182#endif
183
184typedef word_t thread_control_flag_t;
185
186exception_t invokeTCB_Suspend(tcb_t *thread);
187exception_t invokeTCB_Resume(tcb_t *thread);
188#ifdef CONFIG_KERNEL_MCS
189exception_t invokeTCB_ThreadControlCaps(tcb_t *target, cte_t *slot,
190                                        cap_t fh_newCap, cte_t *fh_srcSlot,
191                                        cap_t th_newCap, cte_t *th_srcSlot,
192                                        cap_t cRoot_newCap, cte_t *cRoot_srcSlot,
193                                        cap_t vRoot_newCap, cte_t *vRoot_srcSlot,
194                                        word_t bufferAddr, cap_t bufferCap,
195                                        cte_t *bufferSrcSlot,
196                                        thread_control_flag_t updateFlags);
197exception_t invokeTCB_ThreadControlSched(tcb_t *target, cte_t *slot,
198                                         cap_t fh_newCap, cte_t *fh_srcSlot,
199                                         prio_t mcp, prio_t priority,
200                                         sched_context_t *sc,
201                                         thread_control_flag_t updateFlags);
202#else
203exception_t invokeTCB_ThreadControl(tcb_t *target, cte_t *slot, cptr_t faultep,
204                                    prio_t mcp, prio_t priority, cap_t cRoot_newCap,
205                                    cte_t *cRoot_srcSlot, cap_t vRoot_newCap,
206                                    cte_t *vRoot_srcSlot, word_t bufferAddr,
207                                    cap_t bufferCap, cte_t *bufferSrcSlot,
208                                    thread_control_flag_t updateFlags);
209#endif
210exception_t invokeTCB_CopyRegisters(tcb_t *dest, tcb_t *src,
211                                    bool_t suspendSource, bool_t resumeTarget,
212                                    bool_t transferFrame, bool_t transferInteger,
213                                    word_t transferArch);
214exception_t invokeTCB_ReadRegisters(tcb_t *src, bool_t suspendSource,
215                                    word_t n, word_t arch, bool_t call);
216exception_t invokeTCB_WriteRegisters(tcb_t *dest, bool_t resumeTarget,
217                                     word_t n, word_t arch, word_t *buffer);
218exception_t invokeTCB_NotificationControl(tcb_t *tcb, notification_t *ntfnPtr);
219
220cptr_t PURE getExtraCPtr(word_t *bufferPtr, word_t i);
221void setExtraBadge(word_t *bufferPtr, word_t badge, word_t i);
222
223exception_t lookupExtraCaps(tcb_t *thread, word_t *bufferPtr, seL4_MessageInfo_t info);
224word_t setMRs_syscall_error(tcb_t *thread, word_t *receiveIPCBuffer);
225word_t CONST Arch_decodeTransfer(word_t flags);
226exception_t CONST Arch_performTransfer(word_t arch, tcb_t *tcb_src,
227                                       tcb_t *tcb_dest);
228
229#ifdef ENABLE_SMP_SUPPORT
230void Arch_migrateTCB(tcb_t *thread);
231#endif /* ENABLE_SMP_SUPPORT */
232
233#ifdef CONFIG_DEBUG_BUILD
234void setThreadName(tcb_t *thread, const char *name);
235#endif /* CONFIG_DEBUG_BUILD */
236
237