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))
19 compile_assert(tcb_name_fits, TCB_NAME_LENGTH > 0)
20 #endif
21 
22 struct tcb_queue {
23     tcb_t *head;
24     tcb_t *end;
25 };
26 typedef struct tcb_queue tcb_queue_t;
27 
setMR(tcb_t * receiver,word_t * receiveIPCBuffer,unsigned int offset,word_t reg)28 static 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 
44 void tcbSchedEnqueue(tcb_t *tcb);
45 void tcbSchedAppend(tcb_t *tcb);
46 void tcbSchedDequeue(tcb_t *tcb);
47 
48 #ifdef CONFIG_DEBUG_BUILD
49 void tcbDebugAppend(tcb_t *tcb);
50 void tcbDebugRemove(tcb_t *tcb);
51 #endif
52 #ifdef CONFIG_KERNEL_MCS
53 void tcbReleaseRemove(tcb_t *tcb);
54 void tcbReleaseEnqueue(tcb_t *tcb);
55 tcb_t *tcbReleaseDequeue(void);
56 #endif
57 
58 #ifdef ENABLE_SMP_SUPPORT
59 void remoteQueueUpdate(tcb_t *tcb);
60 void 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 */
tcbEPAppend(tcb_t * tcb,tcb_queue_t queue)82 static 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 
114 tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
115 
116 #else
117 tcb_queue_t tcbEPAppend(tcb_t *tcb, tcb_queue_t queue);
118 tcb_queue_t tcbEPDequeue(tcb_t *tcb, tcb_queue_t queue);
119 
120 void setupCallerCap(tcb_t *sender, tcb_t *receiver, bool_t canGrant);
121 void deleteCallerCap(tcb_t *receiver);
122 #endif
123 
124 word_t copyMRs(tcb_t *sender, word_t *sendBuf, tcb_t *receiver,
125                word_t *recvBuf, word_t n);
126 exception_t decodeTCBInvocation(word_t invLabel, word_t length, cap_t cap,
127                                 cte_t *slot, bool_t call, word_t *buffer);
128 exception_t decodeCopyRegisters(cap_t cap, word_t length, word_t *buffer);
129 exception_t decodeReadRegisters(cap_t cap, word_t length, bool_t call,
130                                 word_t *buffer);
131 exception_t decodeWriteRegisters(cap_t cap, word_t length, word_t *buffer);
132 exception_t decodeTCBConfigure(cap_t cap, word_t length,
133                                cte_t *slot, word_t *buffer);
134 exception_t decodeSetPriority(cap_t cap, word_t length, word_t *buffer);
135 exception_t decodeSetMCPriority(cap_t cap, word_t length, word_t *buffer);
136 #ifdef CONFIG_KERNEL_MCS
137 exception_t decodeSetSchedParams(cap_t cap, word_t length, cte_t *slot, word_t *buffer);
138 #else
139 exception_t decodeSetSchedParams(cap_t cap, word_t length, word_t *buffer);
140 #endif
141 exception_t decodeSetIPCBuffer(cap_t cap, word_t length,
142                                cte_t *slot, word_t *buffer);
143 exception_t decodeSetSpace(cap_t cap, word_t length,
144                            cte_t *slot, word_t *buffer);
145 exception_t decodeDomainInvocation(word_t invLabel, word_t length, word_t *buffer);
146 exception_t decodeBindNotification(cap_t cap);
147 exception_t decodeUnbindNotification(cap_t cap);
148 #ifdef CONFIG_KERNEL_MCS
149 exception_t decodeSetTimeoutEndpoint(cap_t cap, cte_t *slot);
150 #endif
151 
152 
153 #ifdef CONFIG_KERNEL_MCS
154 enum thread_control_caps_flag {
155     thread_control_caps_update_ipc_buffer = 0x1,
156     thread_control_caps_update_space = 0x2,
157     thread_control_caps_update_fault = 0x4,
158     thread_control_caps_update_timeout = 0x8,
159 };
160 
161 enum thread_control_sched_flag {
162     thread_control_sched_update_priority = 0x1,
163     thread_control_sched_update_mcp = 0x2,
164     thread_control_sched_update_sc = 0x4,
165     thread_control_sched_update_fault = 0x8,
166 };
167 #else
168 enum thread_control_flag {
169     thread_control_update_priority = 0x1,
170     thread_control_update_ipc_buffer = 0x2,
171     thread_control_update_space = 0x4,
172     thread_control_update_mcp = 0x8,
173 #ifdef CONFIG_KERNEL_MCS
174     thread_control_update_sc = 0x10,
175     thread_control_update_fault = 0x20,
176     thread_control_update_timeout = 0x40,
177 #endif
178 };
179 #endif
180 
181 typedef word_t thread_control_flag_t;
182 
183 exception_t invokeTCB_Suspend(tcb_t *thread);
184 exception_t invokeTCB_Resume(tcb_t *thread);
185 #ifdef CONFIG_KERNEL_MCS
186 exception_t invokeTCB_ThreadControlCaps(tcb_t *target, cte_t *slot,
187                                         cap_t fh_newCap, cte_t *fh_srcSlot,
188                                         cap_t th_newCap, cte_t *th_srcSlot,
189                                         cap_t cRoot_newCap, cte_t *cRoot_srcSlot,
190                                         cap_t vRoot_newCap, cte_t *vRoot_srcSlot,
191                                         word_t bufferAddr, cap_t bufferCap,
192                                         cte_t *bufferSrcSlot,
193                                         thread_control_flag_t updateFlags);
194 exception_t invokeTCB_ThreadControlSched(tcb_t *target, cte_t *slot,
195                                          cap_t fh_newCap, cte_t *fh_srcSlot,
196                                          prio_t mcp, prio_t priority,
197                                          sched_context_t *sc,
198                                          thread_control_flag_t updateFlags);
199 #else
200 exception_t invokeTCB_ThreadControl(tcb_t *target, cte_t *slot, cptr_t faultep,
201                                     prio_t mcp, prio_t priority, cap_t cRoot_newCap,
202                                     cte_t *cRoot_srcSlot, cap_t vRoot_newCap,
203                                     cte_t *vRoot_srcSlot, word_t bufferAddr,
204                                     cap_t bufferCap, cte_t *bufferSrcSlot,
205                                     thread_control_flag_t updateFlags);
206 #endif
207 exception_t invokeTCB_CopyRegisters(tcb_t *dest, tcb_t *src,
208                                     bool_t suspendSource, bool_t resumeTarget,
209                                     bool_t transferFrame, bool_t transferInteger,
210                                     word_t transferArch);
211 exception_t invokeTCB_ReadRegisters(tcb_t *src, bool_t suspendSource,
212                                     word_t n, word_t arch, bool_t call);
213 exception_t invokeTCB_WriteRegisters(tcb_t *dest, bool_t resumeTarget,
214                                      word_t n, word_t arch, word_t *buffer);
215 exception_t invokeTCB_NotificationControl(tcb_t *tcb, notification_t *ntfnPtr);
216 
217 cptr_t PURE getExtraCPtr(word_t *bufferPtr, word_t i);
218 void setExtraBadge(word_t *bufferPtr, word_t badge, word_t i);
219 
220 exception_t lookupExtraCaps(tcb_t *thread, word_t *bufferPtr, seL4_MessageInfo_t info);
221 word_t setMRs_syscall_error(tcb_t *thread, word_t *receiveIPCBuffer);
222 word_t CONST Arch_decodeTransfer(word_t flags);
223 exception_t CONST Arch_performTransfer(word_t arch, tcb_t *tcb_src,
224                                        tcb_t *tcb_dest);
225 
226 #ifdef ENABLE_SMP_SUPPORT
227 void Arch_migrateTCB(tcb_t *thread);
228 #endif /* ENABLE_SMP_SUPPORT */
229 
230 #ifdef CONFIG_DEBUG_BUILD
231 void setThreadName(tcb_t *thread, const char *name);
232 #endif /* CONFIG_DEBUG_BUILD */
233 
234