1/*
2 * Copyright 2017, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13/**
14 *
15 * Provides basic thread configuration/starting/cleanup functions.
16 *
17 * Any other operations (start, stop, resume) should use the seL4 API directly on
18 * sel4utils_thread_t->tcb.cptr.
19 *
20 */
21#pragma once
22
23#include <autoconf.h>
24#include <sel4utils/gen_config.h>
25
26#include <sel4/sel4.h>
27#include <stdbool.h>
28#include <vka/vka.h>
29
30#include <vspace/vspace.h>
31#include <sel4utils/thread_config.h>
32
33#ifdef CONFIG_DEBUG_BUILD
34#define NAME_THREAD(_tcbcap, _name)   seL4_DebugNameThread(_tcbcap, _name);
35#else
36#define NAME_THREAD(_tcbcap, _name)
37#endif
38
39typedef struct sel4utils_thread {
40    vka_object_t tcb;
41    vka_object_t sched_context;
42    void *stack_top;
43    void *initial_stack_pointer;
44    size_t stack_size;
45    seL4_CPtr ipc_buffer;
46    seL4_Word ipc_buffer_addr;
47    bool own_sc;
48    bool own_reply;
49    vka_object_t reply;
50} sel4utils_thread_t;
51
52typedef struct sel4utils_checkpoint {
53    /* checkpointed stack */
54    void *stack;
55    seL4_UserContext regs;
56    sel4utils_thread_t *thread;
57    /* stack pointer this checkpoint preserves */
58    uintptr_t sp;
59} sel4utils_checkpoint_t;
60
61typedef void (*sel4utils_thread_entry_fn)(void *arg0, void *arg1, void *ipc_buf);
62
63/**
64 * Configure a thread, allocating any resources required. The thread will start at priority 0.
65 *
66 * If CONFIG_RT is enabled, the thread will not have a scheduling context, so it will not be able to run.
67 *
68 * @param vka initialised vka to allocate objects with
69 * @param parent vspace structure of the thread calling this function, used for temporary mappings
70 * @param alloc initialised vspace structure to allocate virtual memory with
71 * @param fault_endpoint endpoint to set as the threads fault endpoint. Can be 0.
72 * @param cspace the root of the cspace to start the thread in
73 * @param cspace_root_data data for cspace access
74 * @param res an uninitialised sel4utils_thread_t data structure that will be initialised
75 *            after this operation.
76 *
77 * @return 0 on success, -1 on failure. Use CONFIG_DEBUG to see error messages.
78 */
79int sel4utils_configure_thread(vka_t *vka, vspace_t *parent, vspace_t *alloc, seL4_CPtr fault_endpoint,
80                               seL4_CNode cspace, seL4_Word cspace_root_data,
81                               sel4utils_thread_t *res);
82
83/**
84 * As per sel4utils_configure_thread, but using a config struct.
85 */
86int sel4utils_configure_thread_config(vka_t *vka, vspace_t *parent, vspace_t *alloc,
87                                      sel4utils_thread_config_t config, sel4utils_thread_t *res);
88
89/**
90 * Start a thread, allocating any resources required.
91 * The third argument to the thread (in r2 for arm, on stack for ia32) will be the
92 * address of the ipc buffer.
93 *
94 * @param thread      thread data structure that has been initialised with sel4utils_configure_thread
95 * @param entry_point the address that the thread will start at
96 *
97 *                    NOTE: In order for the on-stack argument passing to work for ia32,
98 *                    entry points must be functions.
99 *
100 *                    ie. jumping to this start symbol will work:
101 *
102 *                    void _start(int argc, char **argv) {
103 *                        int ret = main(argc, argv);
104 *                        exit(ret);
105 *                    }
106 *
107 *
108 *                    However, jumping to a start symbol like this:
109 *
110 *                    _start:
111 *                         call main
112 *
113 *                    will NOT work, as call pushes an extra value (the return value)
114 *                    onto the stack. If you really require an assembler stub, it should
115 *                    decrement the stack value to account for this.
116 *
117 *                    ie.
118 *
119 *                    _start:
120 *                         popl %eax
121 *                         call main
122 *
123 *                    This does not apply for arm, as arguments are passed in registers.
124 *
125 *
126 * @param arg0        a pointer to the arguments for this thread. User decides the protocol.
127 * @param arg1        another pointer. User decides the protocol. Note that there are two args here
128 *                    to easily support C standard: int main(int argc, char **argv).
129 * @param resume      1 to start the thread immediately, 0 otherwise.
130 *
131 * @return 0 on success, -1 on failure.
132 */
133int sel4utils_start_thread(sel4utils_thread_t *thread, sel4utils_thread_entry_fn entry_point,
134                           void *arg0, void *arg1, int resume);
135
136/**
137 * Release any resources used by this thread. The thread data structure will not be usable
138 * until sel4utils_thread_configure is called again.
139 *
140 * @param vka the vka interface that this thread was initialised with
141 * @param alloc the allocation interface that this thread was initialised with
142 * @param thread the thread structure that was returned when the thread started
143 */
144void sel4utils_clean_up_thread(vka_t *vka, vspace_t *alloc, sel4utils_thread_t *thread);
145
146/**
147 * Checkpoint a thread at its current state, storing its current register set and stack.
148 *
149 * Note that the heap state is not saved, so threads intending to use this functionality
150 * should not mutate the heap or other state beyond the checkpoint, unless extra functionality
151 * is included to roll these back.
152 *
153 * This should not be called on a currently running thread, and is designed to be called on
154 * threads which are known to be blocked on an seL4_Recv, for checkpointing passive threads on
155 * the mcs kernel (threads without scheduling contexts). The checkpoint is set up that such a
156 * thread can be restarted successfully at the instruction which enters the kernel, with
157 * register state set up specifically for that.
158 *
159 * @param thread     the thread to checkpoint
160 * @param checkpoint pointer to uninitialised checkpoint struct
161 * @param suspend    true if the thread should be suspended
162 *
163 * @return 0 on success.
164 */
165int sel4utils_checkpoint_thread(sel4utils_thread_t *thread, sel4utils_checkpoint_t *checkpoint, bool suspend);
166
167/**
168 * Rollback a thread to a previous checkpoint, restoring its register set and stack.
169 *
170 * This is not atomic and callers should make sure the target thread is stopped or that the
171 * caller is higher priority such that the target is not switched to by the kernel mid-restore.
172 *
173 * @param checkpoint the previously saved checkpoint to restore.
174 * @param free       true if this checkpoint should free all memory allocated, i.e if the checkpoint
175 *                   will not be used again.
176 * @param resume     true if the thread should be resumed immediately.
177 *
178 * @return 0 on success.
179 */
180int sel4utils_checkpoint_restore(sel4utils_checkpoint_t *checkpoint, bool free, bool resume);
181
182/**
183 * Clean up a previously allocated checkpoint.
184 */
185void sel4utils_free_checkpoint(sel4utils_checkpoint_t *checkpoint);
186
187/**
188 * Start a fault handling thread that will print the name of the thread that faulted
189 * as well as debugging information. The thread will start at priority 0.
190 *
191 * If CONFIG_RT it be passive (not have a scheulding context) and will run on the SC of the faulter.
192 *
193 * @param fault_endpoint the fault_endpoint to wait on
194 * @param vka allocator
195 * @param vspace vspace (this library must be mapped into that vspace).
196 * @param cspace the cspace that the fault_endpoint is in
197 * @param data the cspace_data for that cspace (with correct guard)
198 * @param name the name of the thread to print if it faults
199 * @param thread the thread data structure to populate
200 *
201 * @return 0 on success.
202 */
203int sel4utils_start_fault_handler(seL4_CPtr fault_endpoint, vka_t *vka, vspace_t *vspace,
204                                  seL4_CPtr cspace, seL4_Word data, char *name, sel4utils_thread_t *res);
205
206/**
207 * Pretty print a fault message.
208 *
209 * @param tag the message info tag delivered by the fault.
210 * @param name thread name
211 */
212void sel4utils_print_fault_message(seL4_MessageInfo_t tag, const char *name);
213
214/* Set the affinity of a thread, which will cause migration if the thread
215 * is running on a different core.
216 *
217 * On master, only use sched_params_set_core to set the core then call this function.
218 *
219 * If CONFIG_KERNEL_MCS is set, the sched params must be fully populated or the scheduling
220 * context will be empty when it changes core as scheduling parameters of scheduling
221 * contexts are not maintained across migrations.
222 */
223int sel4utils_set_sched_affinity(sel4utils_thread_t *thread, sched_params_t params);
224
225static inline seL4_TCB sel4utils_get_tcb(sel4utils_thread_t *thread)
226{
227    return thread->tcb.cptr;
228}
229
230static inline int sel4utils_suspend_thread(sel4utils_thread_t *thread)
231{
232    return seL4_TCB_Suspend(thread->tcb.cptr);
233}
234
235