1/*
2 * Copyright 2019, 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#include <sel4runtime.h>
13#include <sel4runtime/auxv.h>
14#include <sel4runtime/mode/elf.h>
15#include <sel4runtime/start.h>
16#include <sel4/sel4.h>
17#include <sel4runtime/gen_config.h>
18#include <autoconf.h>
19
20#include "init.h"
21#include "util.h"
22
23// Minimum alignment across all platforms.
24#define MIN_ALIGN_BYTES 16
25#define MIN_ALIGNED __attribute__((aligned (MIN_ALIGN_BYTES)))
26
27// Static TLS for initial thread.
28static char static_tls[CONFIG_SEL4RUNTIME_STATIC_TLS] MIN_ALIGNED = {};
29
30// Thread lookup pointers.
31typedef struct {
32    sel4runtime_uintptr_t tls_base;
33} thread_lookup_t;
34
35// The seL4 runtime environment.
36static struct {
37    char const *process_name;
38
39    // optional bootinfo pointer.
40    seL4_BootInfo *bootinfo;
41
42    /*
43     * The initial thread object is initially set to a static thread
44     * object. It is only used until a TLS is set up for the first
45     * thread.
46     *
47     * Once the TLS has been initialised for the first thread, this is
48     * then set to NULL and the thread local reference should be used.
49     */
50    sel4runtime_uintptr_t initial_thread_tls_base;
51    seL4_CPtr initial_thread_tcb;
52    seL4_IPCBuffer *initial_thread_ipc_buffer;
53
54    // ELF Headers
55    struct {
56        sel4runtime_size_t count;
57        sel4runtime_size_t size;
58        Elf_Phdr *headers;
59    } program_header;
60
61    // TLS images
62    struct {
63        // The location of the initial image in memory.
64        void *image;
65        // The size of the initial image in memory.
66        sel4runtime_size_t image_size;
67        // The size needed to store the full TLS.
68        sel4runtime_size_t memory_size;
69        // The size needed to store the TLS and the thread structure.
70        sel4runtime_size_t region_size;
71        // Alignment needed for the TLS data.
72        sel4runtime_size_t align;
73        // Offset of the TLS data from the thread pointer.
74        sel4runtime_size_t offset;
75    } tls;
76
77    // Argument vector
78    char const *const *argv;
79    int argc;
80
81    // Auxiliary vector
82    auxv_t const *auxv;
83
84    // Environment vector
85    char const *const *envp;
86
87    // Exit callbacks
88    sel4runtime_exit_cb *exit_cb;
89    sel4runtime_pre_exit_cb *pre_exit_cb;
90} env = {
91    /*
92     * Initialise the initial thread as referring to the global thread
93     * object.
94     */
95    .initial_thread_tls_base = (sel4runtime_uintptr_t)SEL4RUNTIME_NULL,
96};
97
98static void name_process(char const *name);
99static void parse_auxv(auxv_t const auxv[]);
100static void parse_phdrs(void);
101static void load_tls_data(Elf_Phdr *header);
102static void try_init_static_tls(void);
103static void copy_tls_data(unsigned char *tls);
104static sel4runtime_uintptr_t tls_base_from_tls_region(unsigned char *tls_region);
105static unsigned char *tls_from_tls_base(sel4runtime_uintptr_t tls_base);
106static unsigned char *tls_from_tls_region(unsigned char *tls_region);
107static thread_lookup_t *thread_lookup_from_tls_region(unsigned char *tls_region);
108static const sel4runtime_size_t tls_region_size(sel4runtime_size_t mem_size, sel4runtime_size_t align);
109static void empty_tls(void);
110static int is_initial_thread(void);
111
112char const *sel4runtime_process_name(void)
113{
114    return env.process_name;
115}
116
117char const *const *sel4runtime_argv(void)
118{
119    return env.argv;
120}
121
122int sel4runtime_argc(void)
123{
124    return env.argc;
125}
126
127char const *const *sel4runtime_envp(void)
128{
129    return env.envp;
130}
131
132auxv_t const *sel4runtime_auxv(void)
133{
134    return env.auxv;
135}
136
137seL4_BootInfo *sel4runtime_bootinfo(void)
138{
139    return env.bootinfo;
140}
141
142sel4runtime_size_t sel4runtime_get_tls_size(void)
143{
144    return env.tls.region_size;
145}
146
147int sel4runtime_initial_tls_enabled(void)
148{
149    /*
150     * If the TLS for the initial process has been activated, the thread
151     * object in the TLS will be used rather than the static thread
152     * object.
153     */
154    return env.initial_thread_tls_base != (sel4runtime_uintptr_t)SEL4RUNTIME_NULL;
155}
156
157sel4runtime_uintptr_t sel4runtime_write_tls_image(void *tls_memory)
158{
159    if (tls_memory == SEL4RUNTIME_NULL) {
160        return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL;
161    }
162
163    copy_tls_data(tls_memory);
164
165    return tls_base_from_tls_region(tls_memory);
166}
167
168sel4runtime_uintptr_t sel4runtime_move_initial_tls(void *tls_memory)
169{
170    if (tls_memory == SEL4RUNTIME_NULL) {
171        return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL;
172    }
173
174    sel4runtime_uintptr_t tls_base = sel4runtime_write_tls_image(tls_memory);
175    if (tls_base == (sel4runtime_uintptr_t)SEL4RUNTIME_NULL) {
176        return (sel4runtime_uintptr_t)SEL4RUNTIME_NULL;
177    }
178
179    sel4runtime_set_tls_base(tls_base);
180
181    if (env.initial_thread_ipc_buffer != SEL4RUNTIME_NULL) {
182        __sel4_ipc_buffer = env.initial_thread_ipc_buffer;
183    }
184
185    env.initial_thread_tls_base = tls_base;
186
187#if defined(CONFIG_DEBUG_BUILD)
188    if (env.initial_thread_tcb && env.initial_thread_ipc_buffer && env.process_name) {
189        // The thread can only be named after the TLS is initialised
190        // and if an IPC buffer is present.
191        seL4_DebugNameThread(env.initial_thread_tcb, env.process_name);
192    }
193#endif
194
195    return env.initial_thread_tls_base;
196}
197
198sel4runtime_exit_cb *sel4runtime_set_exit(sel4runtime_exit_cb *cb)
199{
200    sel4runtime_exit_cb *old = env.exit_cb;
201    env.exit_cb = cb;
202    return old;
203}
204
205sel4runtime_pre_exit_cb *sel4runtime_set_pre_exit(sel4runtime_pre_exit_cb *cb)
206{
207    sel4runtime_pre_exit_cb *old = env.pre_exit_cb;
208    env.pre_exit_cb = cb;
209    return old;
210}
211
212void sel4runtime_exit(int code)
213{
214    if (env.pre_exit_cb != SEL4RUNTIME_NULL) {
215        code = env.pre_exit_cb(code);
216    }
217
218    __sel4runtime_run_destructors();
219
220    /* If the exit is never set this will try and call a NULL function
221     * pointer which should result in a fault. This is as good a way as
222     * any to exit the process if we don't know anything better about
223     * the environment. */
224    env.exit_cb(code);
225}
226
227int __sel4runtime_write_tls_variable(
228    sel4runtime_uintptr_t dest_tls_base,
229    unsigned char *local_tls_dest,
230    unsigned char *src,
231    sel4runtime_size_t bytes
232)
233{
234    sel4runtime_uintptr_t local_tls_base = sel4runtime_get_tls_base();
235    unsigned char *local_tls = tls_from_tls_base(local_tls_base);
236    sel4runtime_size_t offset = local_tls_dest - local_tls;
237    sel4runtime_size_t tls_size = env.tls.memory_size;
238
239    // Write must not go past end of TLS.
240    if (offset > tls_size || offset + bytes > tls_size) {
241        return -1;
242    }
243
244    unsigned char *dest_tls = tls_from_tls_base(dest_tls_base);
245    unsigned char *dest_addr = dest_tls + offset;
246
247    __sel4runtime_memcpy(dest_addr, src, bytes);
248
249    return 0;
250}
251
252void __sel4runtime_load_env(
253    int argc,
254    char const *const *argv,
255    char const *const *envp,
256    auxv_t const auxv[]
257)
258{
259    empty_tls();
260    parse_auxv(auxv);
261    parse_phdrs();
262    if (argc > 0) {
263        name_process(argv[0]);
264    }
265    try_init_static_tls();
266
267    env.argc = argc;
268    env.argv = argv;
269    env.auxv = auxv;
270    env.envp = envp;
271
272    __sel4runtime_run_constructors();
273}
274
275static void name_process(char const *name)
276{
277    env.process_name = name;
278
279    while (name && *name != '\0') {
280        if (*name == '/') {
281            env.process_name = name + 1;
282        }
283
284        name++;
285    }
286}
287
288static void parse_auxv(auxv_t const auxv[])
289{
290    for (int i = 0; auxv[i].a_type != AT_NULL; i++) {
291        switch (auxv[i].a_type) {
292        case AT_PHENT: {
293            env.program_header.size = auxv[i].a_un.a_val;
294            break;
295        }
296        case AT_PHNUM: {
297            env.program_header.count = auxv[i].a_un.a_val;
298            break;
299        }
300        case AT_PHDR: {
301            env.program_header.headers = auxv[i].a_un.a_ptr;
302            break;
303        }
304        case AT_SEL4_BOOT_INFO: {
305            seL4_BootInfo *bootinfo = auxv[i].a_un.a_ptr;
306            if (bootinfo == SEL4RUNTIME_NULL) {
307                break;
308            }
309            env.bootinfo = bootinfo;
310            env.initial_thread_ipc_buffer = bootinfo->ipcBuffer;
311            env.initial_thread_tcb = seL4_CapInitThreadTCB;
312            break;
313        }
314        case AT_SEL4_IPC_BUFFER_PTR: {
315            env.initial_thread_ipc_buffer = auxv[i].a_un.a_ptr;
316            break;
317        }
318        case AT_SEL4_TCB: {
319            env.initial_thread_tcb = auxv[i].a_un.a_val;
320            break;
321        }
322        default:
323            break;
324        }
325    }
326}
327
328static void parse_phdrs(void)
329{
330    for (sel4runtime_size_t h = 0; h < env.program_header.count; h++) {
331        Elf_Phdr *header = &env.program_header.headers[h];
332        switch (header->p_type) {
333        case PT_TLS:
334            load_tls_data(header);
335            break;
336        default:
337            break;
338        }
339    }
340}
341
342static void load_tls_data(Elf_Phdr *header)
343{
344    env.tls.image = (void *) header->p_vaddr;
345    if (header->p_align > MIN_ALIGN_BYTES) {
346        env.tls.align = header->p_align;
347    } else {
348        env.tls.align = MIN_ALIGN_BYTES;
349    }
350    env.tls.image_size = header->p_filesz;
351    env.tls.memory_size = ROUND_UP(header->p_memsz, header->p_align);
352    env.tls.region_size = tls_region_size(
353                              env.tls.memory_size,
354                              env.tls.align
355                          );
356}
357
358static void try_init_static_tls(void)
359{
360    if (env.tls.region_size <= sizeof(static_tls)) {
361        sel4runtime_move_initial_tls(static_tls);
362    }
363}
364
365static void copy_tls_data(unsigned char *tls_region)
366{
367    unsigned char *tls = tls_from_tls_region(tls_region);
368    __sel4runtime_memcpy(tls, env.tls.image, env.tls.image_size);
369    unsigned char *tbss = &tls[env.tls.image_size];
370    __sel4runtime_memset(tbss, 0, env.tls.memory_size - env.tls.image_size);
371
372    thread_lookup_t *lookup = thread_lookup_from_tls_region(tls_region);
373    if (lookup != SEL4RUNTIME_NULL) {
374        lookup->tls_base = tls_base_from_tls_region(tls_region);
375    }
376}
377
378static sel4runtime_uintptr_t tls_base_from_tls_region(unsigned char *tls_region)
379{
380    sel4runtime_uintptr_t tls_base = (sel4runtime_uintptr_t)tls_region;
381#if !defined(TLS_ABOVE_TP)
382    tls_base += env.tls.memory_size;
383#endif
384    return ROUND_UP(tls_base, env.tls.align);
385}
386
387static unsigned char *tls_from_tls_base(sel4runtime_uintptr_t tls_base)
388{
389    sel4runtime_uintptr_t tls_addr = tls_base;
390#if !defined(TLS_ABOVE_TP)
391    tls_addr -= env.tls.memory_size;
392#endif
393#if defined(GAP_ABOVE_TP)
394    tls_addr +=  GAP_ABOVE_TP;
395#endif
396    return (unsigned char *)tls_addr;
397}
398
399static unsigned char *tls_from_tls_region(unsigned char *tls_region)
400{
401    return tls_from_tls_base(tls_base_from_tls_region(tls_region));
402}
403
404static thread_lookup_t *thread_lookup_from_tls_region(
405    unsigned char *tls_region
406)
407{
408#if !defined(TLS_ABOVE_TP)
409    return (thread_lookup_t *)tls_base_from_tls_region(tls_region);
410#else
411    return SEL4RUNTIME_NULL;
412#endif
413}
414
415static const sel4runtime_size_t tls_region_size(sel4runtime_size_t mem_size, sel4runtime_size_t align)
416{
417    return align
418           + ROUND_UP(sizeof(thread_lookup_t), align)
419#if defined(GAP_ABOVE_TP)
420           + ROUND_UP(GAP_ABOVE_TP, align)
421#endif
422           + ROUND_UP(mem_size, align);
423}
424
425static void empty_tls(void)
426{
427    env.tls.image = SEL4RUNTIME_NULL;
428    env.tls.align = MIN_ALIGN_BYTES;
429    env.tls.image_size = 0;
430    env.tls.memory_size = 0;
431    env.tls.region_size = tls_region_size(
432                              env.tls.memory_size,
433                              env.tls.align
434                          );
435}
436
437/*
438 * Check if the executing thread is the inital thread of the process.
439 *
440 * This will optimistically assume that the current thread is the
441 * initial thread of no thread ever had TLS configured.
442 */
443static int is_initial_thread(void)
444{
445    return env.initial_thread_tls_base == (sel4runtime_uintptr_t)SEL4RUNTIME_NULL
446           || sel4runtime_get_tls_base() == env.initial_thread_tls_base;
447}
448